1
0
mirror of https://github.com/axzilla/templui.git synced 2025-02-21 21:52:40 +00:00

Merge pull request #7 from axzilla/form

Form Components
This commit is contained in:
Axel Adrian 2024-11-22 15:30:18 +07:00 committed by GitHub
commit 7b325e90db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 13322 additions and 2293 deletions

View File

@ -1,95 +0,0 @@
# Goilerplate Commit & Release Cheatsheet
## Commit Message Format
`<type>`: `<description>`
## Types
- `feat`: New feature or component
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc)
- `refactor`: Code change that neither fixes a bug nor adds a feature
- `perf`: Code change that improves performance
- `test`: Adding missing tests or correcting existing tests
- `chore`: Changes to the build process or auxiliary tools and libraries
## Examples
- `feat: add Button component`
- `fix: correct Card component padding on mobile`
- `refactor: simplify Modal component logic`
## Breaking Changes
Add `!` after the type for breaking changes:
- `feat!: redesign Form component API`
## Versioning Strategy (0.x.y)
- 0: Remains 0 until the first stable version (1.0.0)
- x: For major changes or feature sets (e.g., 20)
- y: For minor changes, bugfixes, and incremental updates
## Version Increments
- Increase second number (x) for:
- New major features
- Significant API or functionality changes
- Increase third number (y) for:
- Bugfixes
- Small feature additions
- Documentation changes
- Performance optimizations
- Other minor changes
## Release Process
1. Commit changes:
```
git add .
git commit -m "feat: implement XYZ feature"
```
2. Tag and push version:
```
git tag -a v0.20.2 -m "Release v0.20.2"
git push origin main --tags
```
3. Create GitHub Release:
- Go to GitHub > Releases > "Draft a new release"
- Select the created tag
- Title: "Release v0.20.2"
- Description: Brief summary of main changes
- Publish the release
## Go Module Usage
- Install latest version:
```
go get github.com/axzilla/goilerplate@latest
```
- Install specific version:
```
go get github.com/axzilla/goilerplate@v0.20.2
```
- Install development version:
```
go get github.com/axzilla/goilerplate@main
```
Remind users to run `go mod tidy` after changes.
## Transition to 1.0.0
Switch to 1.0.0 when the project:
- Has a stable API
- Is sufficiently tested
- Is ready for production environments
- Offers a solid feature base

View File

@ -6,45 +6,46 @@
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%; --muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%; --muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%; --popover: 0 0% 100%;
--accent-foreground: 240 5.9% 10%; --popover-foreground: 240 10% 3.9%;
--destructive: 0 72.22% 50.59%; --card: 0 0% 100%;
--destructive-foreground: 0 0% 98%; --card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%; --border: 240 5.9% 90%;
--input: 240 5.9% 90%; --input: 240 5.9% 90%;
--ring: 240 5.9% 10%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: 240 10% 3.9%; --background: 20 14.3% 4.1%;
--foreground: 0 0% 98%; --foreground: 0 0% 95%;
--card: 240 10% 3.9%; --muted: 0 0% 15%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%; --muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%; --popover: 0 0% 9%;
--accent-foreground: 0 0% 98%; --popover-foreground: 0 0% 95%;
--destructive: 0 62.8% 30.6%; --card: 24 9.8% 10%;
--destructive-foreground: 0 0% 98%; --card-foreground: 0 0% 95%;
--border: 240 3.7% 15.9%; --border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%; --input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem;
} }
} }
@layer base { @layer base {

View File

@ -449,46 +449,47 @@ video {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%; --muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%; --muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%; --popover: 0 0% 100%;
--accent-foreground: 240 5.9% 10%; --popover-foreground: 240 10% 3.9%;
--destructive: 0 72.22% 50.59%; --card: 0 0% 100%;
--destructive-foreground: 0 0% 98%; --card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%; --border: 240 5.9% 90%;
--input: 240 5.9% 90%; --input: 240 5.9% 90%;
--ring: 240 5.9% 10%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: 240 10% 3.9%; --background: 20 14.3% 4.1%;
--foreground: 0 0% 98%; --foreground: 0 0% 95%;
--card: 240 10% 3.9%; --muted: 0 0% 15%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%; --muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%; --popover: 0 0% 9%;
--accent-foreground: 0 0% 98%; --popover-foreground: 0 0% 95%;
--destructive: 0 62.8% 30.6%; --card: 24 9.8% 10%;
--destructive-foreground: 0 0% 98%; --card-foreground: 0 0% 95%;
--border: 240 3.7% 15.9%; --border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%; --input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem;
} }
* { * {
@ -628,6 +629,30 @@ 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;
}
.visible {
visibility: visible;
}
.invisible {
visibility: hidden;
}
.static { .static {
position: static; position: static;
} }
@ -674,6 +699,10 @@ body {
left: 0px; left: 0px;
} }
.left-1\/2 {
left: 50%;
}
.left-full { .left-full {
left: 100%; left: 100%;
} }
@ -686,6 +715,10 @@ body {
right: 0.5rem; right: 0.5rem;
} }
.right-3 {
right: 0.75rem;
}
.right-4 { .right-4 {
right: 1rem; right: 1rem;
} }
@ -694,10 +727,18 @@ body {
top: 0px; top: 0px;
} }
.top-1\/2 {
top: 50%;
}
.top-2 { .top-2 {
top: 0.5rem; top: 0.5rem;
} }
.top-3 {
top: 0.75rem;
}
.top-full { .top-full {
top: 100%; top: 100%;
} }
@ -819,6 +860,16 @@ body {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
.size-3 {
width: 0.75rem;
height: 0.75rem;
}
.size-4 {
width: 1rem;
height: 1rem;
}
.h-1\/2 { .h-1\/2 {
height: 50%; height: 50%;
} }
@ -839,6 +890,10 @@ body {
height: 4rem; height: 4rem;
} }
.h-2 {
height: 0.5rem;
}
.h-24 { .h-24 {
height: 6rem; height: 6rem;
} }
@ -887,6 +942,10 @@ body {
max-height: 24rem; max-height: 24rem;
} }
.min-h-\[80px\] {
min-height: 80px;
}
.min-h-screen { .min-h-screen {
min-height: 100vh; min-height: 100vh;
} }
@ -955,6 +1014,10 @@ body {
max-width: 80rem; max-width: 80rem;
} }
.max-w-lg {
max-width: 32rem;
}
.max-w-md { .max-w-md {
max-width: 28rem; max-width: 28rem;
} }
@ -987,11 +1050,20 @@ body {
flex-shrink: 0; flex-shrink: 0;
} }
.grow {
flex-grow: 1;
}
.-translate-x-1 { .-translate-x-1 {
--tw-translate-x: -0.25rem; --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)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.-translate-x-1\/2 {
--tw-translate-x: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-x-1\/4 { .-translate-x-1\/4 {
--tw-translate-x: -25%; --tw-translate-x: -25%;
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)); 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));
@ -1002,6 +1074,11 @@ body {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.-translate-y-1\/2 {
--tw-translate-y: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-y-full { .-translate-y-full {
--tw-translate-y: -100%; --tw-translate-y: -100%;
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)); 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));
@ -1012,16 +1089,6 @@ body {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-x-0\.5 {
--tw-translate-x: 0.125rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-x-\[18px\] {
--tw-translate-x: 18px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-x-full { .translate-x-full {
--tw-translate-x: 100%; --tw-translate-x: 100%;
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)); 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));
@ -1042,11 +1109,6 @@ body {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-y-px {
--tw-translate-y: 1px;
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));
}
.scale-100 { .scale-100 {
--tw-scale-x: 1; --tw-scale-x: 1;
--tw-scale-y: 1; --tw-scale-y: 1;
@ -1077,6 +1139,10 @@ body {
user-select: none; user-select: none;
} }
.resize {
resize: both;
}
.list-decimal { .list-decimal {
list-style-type: decimal; list-style-type: decimal;
} }
@ -1196,10 +1262,10 @@ body {
margin-bottom: calc(1rem * var(--tw-space-y-reverse)); margin-bottom: calc(1rem * var(--tw-space-y-reverse));
} }
.space-y-6 > :not([hidden]) ~ :not([hidden]) { .space-y-8 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0; --tw-space-y-reverse: 0;
margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); margin-bottom: calc(2rem * var(--tw-space-y-reverse));
} }
.divide-y > :not([hidden]) ~ :not([hidden]) { .divide-y > :not([hidden]) ~ :not([hidden]) {
@ -1281,11 +1347,6 @@ body {
border-top-width: 1px; border-top-width: 1px;
} }
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.border-border { .border-border {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: hsl(var(--border) / var(--tw-border-opacity)); border-color: hsl(var(--border) / var(--tw-border-opacity));
@ -1358,11 +1419,6 @@ body {
background-color: hsl(var(--muted) / var(--tw-bg-opacity)); background-color: hsl(var(--muted) / var(--tw-bg-opacity));
} }
.bg-muted-foreground {
--tw-bg-opacity: 1;
background-color: hsl(var(--muted-foreground) / var(--tw-bg-opacity));
}
.bg-muted\/50 { .bg-muted\/50 {
background-color: hsl(var(--muted) / 0.5); background-color: hsl(var(--muted) / 0.5);
} }
@ -1475,11 +1531,6 @@ body {
padding-right: 2rem; padding-right: 2rem;
} }
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 { .py-1 {
padding-top: 0.25rem; padding-top: 0.25rem;
padding-bottom: 0.25rem; padding-bottom: 0.25rem;
@ -1735,10 +1786,6 @@ body {
opacity: 1; opacity: 1;
} }
.opacity-50 {
opacity: 0.5;
}
.opacity-80 { .opacity-80 {
opacity: 0.8; opacity: 0.8;
} }
@ -1755,12 +1802,6 @@ body {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
} }
.shadow-md {
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-sm { .shadow-sm {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@ -1796,6 +1837,11 @@ body {
--tw-ring-offset-color: hsl(var(--background) / 1); --tw-ring-offset-color: hsl(var(--background) / 1);
} }
.blur {
--tw-blur: blur(8px);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.filter { .filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
} }
@ -1900,6 +1946,107 @@ body {
color: hsl(var(--muted-foreground) / var(--tw-text-opacity)); color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
} }
.before\:absolute::before {
content: var(--tw-content);
position: absolute;
}
.before\:inset-0::before {
content: var(--tw-content);
inset: 0px;
}
.before\:left-1\/2::before {
content: var(--tw-content);
left: 50%;
}
.before\:top-1\/2::before {
content: var(--tw-content);
top: 50%;
}
.before\:h-1\.5::before {
content: var(--tw-content);
height: 0.375rem;
}
.before\:w-1\.5::before {
content: var(--tw-content);
width: 0.375rem;
}
.before\:-translate-x-1\/2::before {
content: var(--tw-content);
--tw-translate-x: -50%;
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));
}
.before\:-translate-y-1\/2::before {
content: var(--tw-content);
--tw-translate-y: -50%;
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));
}
.before\:rounded-full::before {
content: var(--tw-content);
border-radius: 9999px;
}
.before\:bg-background::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--background) / var(--tw-bg-opacity));
}
.after\:absolute::after {
content: var(--tw-content);
position: absolute;
}
.after\:left-0\.5::after {
content: var(--tw-content);
left: 0.125rem;
}
.after\:top-0\.5::after {
content: var(--tw-content);
top: 0.125rem;
}
.after\:h-5::after {
content: var(--tw-content);
height: 1.25rem;
}
.after\:w-5::after {
content: var(--tw-content);
width: 1.25rem;
}
.after\:rounded-full::after {
content: var(--tw-content);
border-radius: 9999px;
}
.after\:bg-muted-foreground::after {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--muted-foreground) / var(--tw-bg-opacity));
}
.after\:transition-all::after {
content: var(--tw-content);
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.after\:content-\[\'\'\]::after {
--tw-content: '';
content: var(--tw-content);
}
.checked\:border-primary:checked { .checked\:border-primary:checked {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: hsl(var(--primary) / var(--tw-border-opacity)); border-color: hsl(var(--primary) / var(--tw-border-opacity));
@ -1910,6 +2057,17 @@ body {
background-color: hsl(var(--primary) / var(--tw-bg-opacity)); background-color: hsl(var(--primary) / var(--tw-bg-opacity));
} }
.checked\:before\:visible:checked::before {
content: var(--tw-content);
visibility: visible;
}
.checked\:before\:bg-primary:checked::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.hover\:bg-accent:hover { .hover\:bg-accent:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: hsl(var(--accent) / var(--tw-bg-opacity)); background-color: hsl(var(--accent) / var(--tw-bg-opacity));
@ -1993,6 +2151,22 @@ body {
outline-offset: 2px; 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 { .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-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); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -2008,6 +2182,19 @@ body {
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity)); --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
} }
.focus\:ring-ring:focus {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
}
.focus\:ring-offset-2:focus {
--tw-ring-offset-width: 2px;
}
.checked\:focus\:outline-primary:focus:checked {
outline-color: hsl(var(--primary) / 1);
}
.focus-visible\:outline-none:focus-visible { .focus-visible\:outline-none:focus-visible {
outline: 2px solid transparent; outline: 2px solid transparent;
outline-offset: 2px; outline-offset: 2px;
@ -2034,6 +2221,14 @@ body {
--tw-ring-offset-width: 2px; --tw-ring-offset-width: 2px;
} }
.focus-visible\:ring-offset-background:focus-visible {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
.active\:outline-offset-0:active {
outline-offset: 0px;
}
.disabled\:pointer-events-none:disabled { .disabled\:pointer-events-none:disabled {
pointer-events: none; pointer-events: none;
} }
@ -2064,24 +2259,30 @@ body {
opacity: 1; opacity: 1;
} }
.peer:checked ~ .peer-checked\:visible {
visibility: visible;
}
.peer:checked ~ .peer-checked\:bg-primary { .peer:checked ~ .peer-checked\:bg-primary {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity)); background-color: hsl(var(--primary) / var(--tw-bg-opacity));
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-2 { .peer:checked ~ .peer-checked\:text-foreground {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-text-opacity: 1;
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); color: hsl(var(--foreground) / var(--tw-text-opacity));
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-ring { .peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
--tw-ring-opacity: 1; content: var(--tw-content);
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity)); --tw-translate-x: 16px;
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));
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-offset-2 { .peer:checked ~ .peer-checked\:after\:bg-secondary::after {
--tw-ring-offset-width: 2px; content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
} }
.peer:disabled ~ .peer-disabled\:cursor-not-allowed { .peer:disabled ~ .peer-disabled\:cursor-not-allowed {
@ -2273,6 +2474,70 @@ body {
} }
} }
.\[\&\:\:-moz-range-thumb\]\:h-4::-moz-range-thumb {
height: 1rem;
}
.\[\&\:\:-moz-range-thumb\]\:w-4::-moz-range-thumb {
width: 1rem;
}
.\[\&\:\:-moz-range-thumb\]\:rounded-full::-moz-range-thumb {
border-radius: 9999px;
}
.\[\&\:\:-moz-range-thumb\]\:border-0::-moz-range-thumb {
border-width: 0px;
}
.\[\&\:\:-moz-range-thumb\]\:bg-primary::-moz-range-thumb {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.\[\&\:\:-moz-range-thumb\]\:hover\:bg-primary\/90:hover::-moz-range-thumb {
background-color: hsl(var(--primary) / 0.9);
}
.\[\&\:\:-webkit-slider-thumb\]\:h-4::-webkit-slider-thumb {
height: 1rem;
}
.\[\&\:\:-webkit-slider-thumb\]\:w-4::-webkit-slider-thumb {
width: 1rem;
}
.\[\&\:\:-webkit-slider-thumb\]\:appearance-none::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
}
.\[\&\:\:-webkit-slider-thumb\]\:rounded-full::-webkit-slider-thumb {
border-radius: 9999px;
}
.\[\&\:\:-webkit-slider-thumb\]\:bg-primary::-webkit-slider-thumb {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.\[\&\:\:-webkit-slider-thumb\]\:hover\:bg-primary\/90:hover::-webkit-slider-thumb {
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) { .\[\&\:has\(svg\)\]\:pl-11:has(svg) {
padding-left: 2.75rem; padding-left: 2.75rem;
} }

View File

@ -35,8 +35,11 @@ func main() {
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input())) 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/modal", templ.Handler(pages.Modal()))
mux.Handle("GET /docs/components/radio-group", templ.Handler(pages.RadioGroup())) mux.Handle("GET /docs/components/radio-group", templ.Handler(pages.RadioGroup()))
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/sheet", templ.Handler(pages.Sheet()))
mux.Handle("GET /docs/components/slider", templ.Handler(pages.Slider()))
mux.Handle("GET /docs/components/tabs", templ.Handler(pages.Tabs())) mux.Handle("GET /docs/components/tabs", templ.Handler(pages.Tabs()))
mux.Handle("GET /docs/components/textarea", templ.Handler(pages.Textarea()))
mux.Handle("GET /docs/components/toggle", templ.Handler(pages.Toggle())) mux.Handle("GET /docs/components/toggle", templ.Handler(pages.Toggle()))
fmt.Println("Server is running on http://localhost:8090") fmt.Println("Server is running on http://localhost:8090")

View File

@ -81,14 +81,26 @@ var Sections = []Section{
Text: "Radio Group", Text: "Radio Group",
Href: "/docs/components/radio-group", Href: "/docs/components/radio-group",
}, },
{
Text: "Select",
Href: "/docs/components/select",
},
{ {
Text: "Sheet", Text: "Sheet",
Href: "/docs/components/sheet", Href: "/docs/components/sheet",
}, },
{
Text: "Slider",
Href: "/docs/components/slider",
},
{ {
Text: "Tabs", Text: "Tabs",
Href: "/docs/components/tabs", Href: "/docs/components/tabs",
}, },
{
Text: "Textarea",
Href: "/docs/components/textarea",
},
{ {
Text: "Toggle", Text: "Toggle",
Href: "/docs/components/toggle", Href: "/docs/components/toggle",

View File

@ -60,7 +60,6 @@ templ BaseLayout() {
class="h-full flex flex-col transition-colors duration-200" class="h-full flex flex-col transition-colors duration-200"
:class="{'bg-white text-black': appTheme === 'light', 'text-white': appTheme === 'dark'}" :class="{'bg-white text-black': appTheme === 'light', 'text-white': appTheme === 'dark'}"
> >
<div class="page-loader">Loading...</div>
<div class="flex flex-col min-h-screen"> <div class="flex flex-col min-h-screen">
{ children... } { children... }
</div> </div>

View File

@ -0,0 +1,41 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/showcase"
"github.com/axzilla/goilerplate/pkg/components"
)
templ Select() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Select</h1>
<p class="mb-4 text-muted-foreground">
A dropdown menu for selecting a single value from a list of options.
</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.SelectShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("select.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("select.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -0,0 +1,39 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/showcase"
"github.com/axzilla/goilerplate/pkg/components"
)
templ Slider() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Slider</h1>
<p class="mb-4 text-muted-foreground">An input where the user selects a value from within a given range.</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.SliderShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("slider.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("slider.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -0,0 +1,39 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/showcase"
"github.com/axzilla/goilerplate/pkg/components"
)
templ Textarea() {
@layouts.DocsLayout() {
<div>
<div class="mb-16">
<h1 class="text-3xl font-bold mb-2">Textarea</h1>
<p class="mb-4 text-muted-foreground">A multi-line text input field that allows users to enter longer text content.</p>
</div>
@components.Tabs(components.TabsProps{
Tabs: []components.Tab{
{
ID: "preview",
Title: "Preview",
Content: showcase.TextareaShowcase(),
},
{
ID: "code",
Title: "Code",
Content: CodeSnippetFromEmbedded("textarea.templ", "go", showcase.TemplFiles),
},
{
ID: "component",
Title: "Component",
Content: CodeSnippetFromEmbedded("textarea.templ", "go", components.TemplFiles),
},
},
TabsContainerClass: "md:w-1/2",
ContentContainerClass: "w-full",
})
</div>
}
}

View File

@ -1,5 +1,3 @@
// internals/ui/pages/theme_customizer.templ
package pages package pages
import ( import (
@ -70,7 +68,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{ @components.Input(components.InputProps{
ID: "username", ID: "username",
Name: "username", Name: "username",
Type: components.Text, Type: components.InputTypeText,
Placeholder: "Enter your username", Placeholder: "Enter your username",
}) })
</div> </div>
@ -79,7 +77,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{ @components.Input(components.InputProps{
ID: "email", ID: "email",
Name: "email", Name: "email",
Type: components.Email, Type: components.InputTypeEmail,
Placeholder: "Enter your email", Placeholder: "Enter your email",
}) })
</div> </div>
@ -88,7 +86,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{ @components.Input(components.InputProps{
ID: "password", ID: "password",
Name: "password", Name: "password",
Type: components.Password, Type: components.InputTypePassword,
Placeholder: "Enter your password", Placeholder: "Enter your password",
}) })
</div> </div>
@ -103,28 +101,26 @@ templ ThemePreview() {
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
<label class="text-sm font-medium">Preferred Contact Method</label> <label class="text-sm font-medium">Preferred Contact Method</label>
@components.RadioGroup(components.RadioGroupProps{DefaultValue: "email", Name: "contact-method"}) { @components.RadioGroup(components.RadioGroupProps{Name: "contact-method"}) {
<div class="space-y-2"> @components.RadioGroupItem(components.RadioGroupItemProps{
@components.RadioGroupItem(components.RadioGroupItemProps{ Value: "email",
Value: "email", ID: "contact-email",
ID: "contact-email", Name: "contact-method",
Name: "contact-method", Label: templ.Raw("Email"),
Label: templ.Raw("Email"), })
}) @components.RadioGroupItem(components.RadioGroupItemProps{
@components.RadioGroupItem(components.RadioGroupItemProps{ Value: "phone",
Value: "phone", ID: "contact-phone",
ID: "contact-phone", Name: "contact-method",
Name: "contact-method", Label: templ.Raw("Phone"),
Label: templ.Raw("Phone"), })
}) @components.RadioGroupItem(components.RadioGroupItemProps{
@components.RadioGroupItem(components.RadioGroupItemProps{ Value: "mail",
Value: "mail", ID: "contact-mail",
ID: "contact-mail", Name: "contact-method",
Name: "contact-method", Label: templ.Raw("Physical Mail"),
Label: templ.Raw("Physical Mail"), Attributes: templ.Attributes{"disabled": "true"},
Disabled: "true", })
})
</div>
} }
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
@ -141,7 +137,7 @@ templ ThemePreview() {
ID: "notifications", ID: "notifications",
Name: "notifications", Name: "notifications",
LabelRight: "Enable notifications", LabelRight: "Enable notifications",
Checked: "true", Attributes: templ.Attributes{"checked": "true"},
}) })
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
@ -149,7 +145,7 @@ templ ThemePreview() {
ID: "beta", ID: "beta",
Name: "beta", Name: "beta",
LabelRight: "Join beta program", LabelRight: "Join beta program",
Disabled: "true", Attributes: templ.Attributes{"disabled": "true"},
}) })
</div> </div>
</div> </div>

View File

@ -17,32 +17,31 @@ templ CheckboxShowcase() {
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Checked Checkbox</h2> <h2 class="font-semibold mb-2">Checked Checkbox</h2>
@components.Checkbox(components.CheckboxProps{ @components.Checkbox(components.CheckboxProps{
ID: "checked-checkbox", ID: "checked-checkbox",
Name: "newsletter", Name: "newsletter",
Value: "subscribe", Value: "subscribe",
Label: "Receive newsletter", Label: "Receive newsletter",
Checked: "true", Attributes: templ.Attributes{"checked": "true"},
}) })
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Disabled Checkbox</h2> <h2 class="font-semibold mb-2">Disabled Checkbox</h2>
@components.Checkbox(components.CheckboxProps{ @components.Checkbox(components.CheckboxProps{
ID: "disabled-checkbox", ID: "disabled-checkbox",
Name: "disabled", Name: "disabled",
Value: "disabled", Value: "disabled",
Label: "Disabled option", Label: "Disabled option",
Disabled: "true", Attributes: templ.Attributes{"disabled": "true"},
}) })
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Disabled Checked Checkbox</h2> <h2 class="font-semibold mb-2">Disabled Checked Checkbox</h2>
@components.Checkbox(components.CheckboxProps{ @components.Checkbox(components.CheckboxProps{
ID: "disabled-checked-checkbox", ID: "disabled-checked-checkbox",
Name: "disabled-checked", Name: "disabled-checked",
Value: "disabled-checked", Value: "disabled-checked",
Label: "Disabled checked option", Label: "Disabled checked option",
Checked: "true", Attributes: templ.Attributes{"checked": "true", "disabled": "true"},
Disabled: "true",
}) })
</div> </div>
<div class="mb-8"> <div class="mb-8">

View File

@ -7,9 +7,15 @@ templ InputShowcase() {
<div> <div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Default</h2> <h2 class="font-semibold mb-2">Default</h2>
@components.Input(components.InputProps{
Type: "email",
})
</div>
<div class="mb-8">
<h2 class="font-semibold mb-2">With Placeholder</h2>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: "email", Type: "email",
Placeholder: "Email", Placeholder: "e.g. john@doe.com",
}) })
</div> </div>
<div class="mb-8"> <div class="mb-8">
@ -23,54 +29,45 @@ templ InputShowcase() {
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Disabled</h2> <h2 class="font-semibold mb-2">Disabled</h2>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: "email", Type: "email",
Placeholder: "Email", Attributes: templ.Attributes{"disabled": "true"},
Disabled: "true",
}) })
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">With Label</h2> <h2 class="font-semibold mb-2">With Label</h2>
<div class="grid w-full max-w-sm items-center gap-1.5"> <div class="grid w-full max-w-sm items-center gap-1.5">
<label for="email" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Email
</label>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
ID: "email", ID: "email",
Type: "email", Type: "email",
Placeholder: "Email", Label: "Email",
}) })
</div> </div>
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">With Button</h2> <h2 class="font-semibold mb-2">With Description</h2>
<div class="flex w-full max-w-sm items-center space-x-2"> @components.Input(components.InputProps{
@components.Input(components.InputProps{ ID: "email",
Type: "email", Type: "email",
Placeholder: "Email", Description: "This is your accounts email address.",
}) })
@components.Button(components.ButtonProps{
Type: "submit",
Text: "Subscribe",
})
</div>
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="font-semibold mb-2">Form</h2> <h2 class="font-semibold mb-2">With Error</h2>
<form class="w-full max-w-sm space-y-6"> @components.Input(components.InputProps{
<div class="space-y-2"> ID: "username",
<label for="username" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"> Error: "Username must be more then 2 characters",
Username })
</label> </div>
@components.Input(components.InputProps{ <div class="mb-8">
ID: "username", <h2 class="font-semibold mb-2">Advanced</h2>
}) @components.Input(components.InputProps{
<p class="text-sm text-muted-foreground m-0">This is your public display name.</p> ID: "username",
</div> Label: "Username",
@components.Button(components.ButtonProps{ Placeholder: "e.g. john123",
Type: "submit", Description: "This is your public display name.",
Text: "Submit", Value: "",
}) Error: "Username must be more then 2 characters",
</form> })
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,35 +1,30 @@
package showcase package showcase
import ( import "github.com/axzilla/goilerplate/pkg/components"
"github.com/axzilla/goilerplate/pkg/components"
)
templ RadioGroupShowcase() { templ RadioGroupShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4"> <div class="flex justify-center items-center border rounded-md py-16 px-4">
<div> @components.RadioGroup(components.RadioGroupProps{}) {
@components.RadioGroup(components.RadioGroupProps{DefaultValue: "comfortable", Name: "view-mode"}) { @components.RadioGroupItem(components.RadioGroupItemProps{
<div class="space-y-2"> Value: "default",
@components.RadioGroupItem(components.RadioGroupItemProps{ ID: "r1",
Value: "default", Name: "view-mode",
ID: "r1", Label: templ.Raw("Default"),
Name: "view-mode", Attributes: templ.Attributes{"checked": true},
Label: templ.Raw("Default"), })
}) @components.RadioGroupItem(components.RadioGroupItemProps{
@components.RadioGroupItem(components.RadioGroupItemProps{ Value: "comfortable",
Value: "comfortable", ID: "r2",
ID: "r2", Name: "view-mode",
Name: "view-mode", Label: templ.Raw("Disabled"),
Disabled: "true", Attributes: templ.Attributes{"disabled": true},
Label: templ.Raw("Comfortable"), })
}) @components.RadioGroupItem(components.RadioGroupItemProps{
@components.RadioGroupItem(components.RadioGroupItemProps{ Value: "compact",
Value: "compact", ID: "r3",
ID: "r3", Name: "view-mode",
Name: "view-mode", Label: templ.Raw("Compact"),
Label: templ.Raw("Compact"), })
}) }
</div>
}
</div>
</div> </div>
} }

View File

@ -0,0 +1,66 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
var xxx = "banana"
templ SelectShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div class="w-full max-w-xs space-y-8">
<div>
<h2 class="font-semibold mb-4">Default Select</h2>
@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>
<div>
<h2 class="font-semibold mb-4">With Placeholder</h2>
@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>
<div>
<h2 class="font-semibold mb-4">Selected Value</h2>
@components.Select(components.SelectProps{
ID: "selected",
Name: "selected",
Placeholder: "Select a fruit",
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>
<div>
<h2 class="font-semibold mb-4">Disabled Select</h2>
@components.Select(components.SelectProps{
ID: "disabled",
Name: "disabled",
Placeholder: "Select is disabled",
Attributes: templ.Attributes{":disabled": "true"},
Options: []components.SelectOption{
{Label: "Option 1", Value: "1"},
{Label: "Option 2", Value: "2"},
},
})
</div>
</div>
</div>
}

View File

@ -0,0 +1,79 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div class="space-y-8 w-full max-w-lg">
<div>
<h2 class="font-semibold mb-4">Default Slider</h2>
@components.Slider(components.SliderProps{
ID: "default",
Name: "default",
Label: "Volume",
Value: 50,
Min: 0,
Max: 100,
Step: 1,
ShowValue: true,
})
</div>
<div>
<h2 class="font-semibold mb-4">With Label</h2>
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Label: "Volume",
Value: 75,
Min: 0,
Max: 100,
Step: 1,
ShowValue: true,
ValueFormat: "%",
})
</div>
<div>
<h2 class="font-semibold mb-4">Temperature Range</h2>
@components.Slider(components.SliderProps{
ID: "temperature",
Name: "temperature",
Label: "Temperature",
Value: 23,
Min: -20,
Max: 40,
Step: 1,
ShowValue: true,
ValueFormat: "°C",
})
</div>
<div>
<h2 class="font-semibold mb-4">Steps</h2>
@components.Slider(components.SliderProps{
ID: "steps",
Name: "steps",
Label: "Zoom Level",
Value: 100,
Min: 0,
Max: 200,
Step: 25,
ShowValue: true,
ValueFormat: "%",
})
</div>
<div>
<h2 class="font-semibold mb-4">Disabled</h2>
@components.Slider(components.SliderProps{
ID: "disabled",
Name: "disabled",
Label: "Disabled Slider",
Value: 20,
Min: -20,
Max: 200,
Step: 20,
Disabled: true,
ShowValue: true,
})
</div>
</div>
</div>
}

View File

@ -38,7 +38,7 @@ templ AccountTab() {
<div class="space-y-1"> <div class="space-y-1">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">Name</label> <label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">Name</label>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: components.Text, Type: components.InputTypeText,
Placeholder: "Name", Placeholder: "Name",
ID: "name", ID: "name",
Value: "John Doe", Value: "John Doe",
@ -47,7 +47,7 @@ templ AccountTab() {
<div class="space-y-1"> <div class="space-y-1">
<label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="username">Username</label> <label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="username">Username</label>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: components.Text, Type: components.InputTypeText,
Placeholder: "Username", Placeholder: "Username",
ID: "username", ID: "username",
Value: "@johndoe", Value: "@johndoe",
@ -78,7 +78,7 @@ templ PasswordTab() {
Current Password Current Password
</label> </label>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: components.Password, Type: components.InputTypePassword,
Placeholder: "Current Password", Placeholder: "Current Password",
ID: "current_password", ID: "current_password",
}) })
@ -88,7 +88,7 @@ templ PasswordTab() {
New Password New Password
</label> </label>
@components.Input(components.InputProps{ @components.Input(components.InputProps{
Type: components.Password, Type: components.InputTypePassword,
Placeholder: "New Password", Placeholder: "New Password",
ID: "new_password", ID: "new_password",
}) })

View File

@ -0,0 +1,71 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div class="space-y-8 w-full max-w-lg">
<div>
<h2 class="font-semibold mb-4">Default Textarea (3 rows)</h2>
@components.Textarea(components.TextareaProps{
ID: "default",
Name: "default",
Placeholder: "Type your message here.",
})
</div>
<div>
<h2 class="font-semibold mb-4">Tall Textarea (6 rows)</h2>
@components.Textarea(components.TextareaProps{
ID: "tall",
Name: "tall",
Placeholder: "Type your message here.",
Rows: 6,
})
</div>
<div>
<h2 class="font-semibold mb-4">With Label & Description</h2>
@components.Textarea(components.TextareaProps{
ID: "with-label",
Name: "with-label",
Label: "Your Message",
Description: "Write a detailed description of your request.",
Placeholder: "Type your message here.",
Rows: 4,
})
</div>
<div>
<h2 class="font-semibold mb-4">With Error</h2>
@components.Textarea(components.TextareaProps{
ID: "with-error",
Name: "with-error",
Label: "Your Message",
Error: "Message is required",
Placeholder: "Type your message here.",
})
</div>
<div>
<h2 class="font-semibold mb-4">Auto-resize</h2>
@components.Textarea(components.TextareaProps{
ID: "auto-resize",
Name: "auto-resize",
Label: "Auto-resizing Textarea",
Description: "This textarea will grow as you type.",
Placeholder: "Start typing to see the magic...",
Rows: 3,
AutoResize: true,
})
</div>
<div>
<h2 class="font-semibold mb-4">Disabled</h2>
@components.Textarea(components.TextareaProps{
ID: "disabled",
Name: "disabled",
Label: "Disabled Textarea",
Value: "This textarea is disabled",
Rows: 3,
Attributes: templ.Attributes{"disabled": "true"},
})
</div>
</div>
</div>
}

View File

@ -29,25 +29,24 @@ templ ToggleShowcase() {
</div> </div>
<div> <div>
<h2 class="font-semibold mb-4">States</h2> <h2 class="font-semibold mb-4">States</h2>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2" x-data="{'xxx': ''}">
@components.Toggle(components.ToggleProps{ @components.Toggle(components.ToggleProps{
ID: "toggle-checked", ID: "toggle-checked",
Name: "toggle-checked", Name: "toggle-checked",
LabelRight: "Checked Toggle", LabelRight: "Checked Toggle",
Checked: "1+1==2", Attributes: templ.Attributes{"x-bind:checked": "true"},
}) })
@components.Toggle(components.ToggleProps{ @components.Toggle(components.ToggleProps{
ID: "toggle-disabled", ID: "toggle-disabled",
Name: "toggle-disabled", Name: "toggle-disabled",
LabelRight: "Disabled Toggle", LabelRight: "Disabled Toggle",
Disabled: "true", Attributes: templ.Attributes{"disabled": "true"},
}) })
@components.Toggle(components.ToggleProps{ @components.Toggle(components.ToggleProps{
ID: "toggle-disabled-checked", ID: "toggle-disabled-checked",
Name: "toggle-disabled-checked", Name: "toggle-disabled-checked",
LabelRight: "Disabled Checked Toggle", LabelRight: "Disabled Checked Toggle",
Disabled: "true", Attributes: templ.Attributes{"checked": "true", "disabled": true},
Checked: "true",
}) })
</div> </div>
</div> </div>

View File

@ -5,61 +5,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// AccordionItem represents a single item in the Accordion component.
type AccordionItem struct { type AccordionItem struct {
// ID is the unique identifier for the accordion item. // ID is the unique identifier for managing accordion item state
// It is used to manage the open/closed state of the item.
ID string ID string
// Trigger is the content of the accordion item's header/trigger. // Trigger is the content shown in the header/trigger area
// This is typically text, but can be any templ.Component. // Can be any templ.Component (typically text)
Trigger templ.Component Trigger templ.Component
// Content is the expandable content of the accordion item. // Content is the expandable content section
// This can be any templ.Component. // Can be any templ.Component
Content templ.Component Content templ.Component
} }
// AccordionProps defines the properties for the Accordion component.
type AccordionProps struct { type AccordionProps struct {
// Items is a slice of AccordionItem structs representing each item in the accordion. // Items contains the accordion sections
Items []AccordionItem Items []AccordionItem
// Class specifies additional CSS classes to apply to the accordion container. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Attributes allows passing additional HTML attributes to the accordion container element. // Attributes for additional HTML attributes and Alpine.js bindings
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Accordion renders an accordion component based on the provided props. // Accordion renders a collapsible content section component with expand/collapse functionality.
// It uses Alpine.js for interactivity and state management. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/accordion
//
// Usage:
//
// @components.Accordion(components.AccordionProps{
// Items: []components.AccordionItem{
// {
// ID: "item-1",
// Trigger: templ.Raw("Is it accessible?"),
// Content: templ.Raw("Yes. It adheres to the WAI-ARIA design pattern."),
// },
// {
// ID: "item-2",
// Trigger: templ.Raw("Is it styled?"),
// Content: templ.Raw("Yes. It comes with default styles that match the other components' aesthetic."),
// },
// },
// Class: "w-full sm:max-w-[70%]",
// Attributes: templ.Attributes{"data-testid": "my-accordion"},
// })
// //
// Props: // Props:
// - Items: A slice of AccordionItem structs, each representing an item in the accordion. // - Items: Array of accordion sections with ID, trigger and content
// - Class: Additional CSS classes to apply to the accordion container. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil // - Attributes: Additional HTML attributes (e.g. data-testid)
templ Accordion(props AccordionProps) { templ Accordion(props AccordionProps) {
<div <div
x-data="{ x-data="{

View File

@ -13,61 +13,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// AccordionItem represents a single item in the Accordion component.
type AccordionItem struct { type AccordionItem struct {
// ID is the unique identifier for the accordion item. // ID is the unique identifier for managing accordion item state
// It is used to manage the open/closed state of the item.
ID string ID string
// Trigger is the content of the accordion item's header/trigger. // Trigger is the content shown in the header/trigger area
// This is typically text, but can be any templ.Component. // Can be any templ.Component (typically text)
Trigger templ.Component Trigger templ.Component
// Content is the expandable content of the accordion item. // Content is the expandable content section
// This can be any templ.Component. // Can be any templ.Component
Content templ.Component Content templ.Component
} }
// AccordionProps defines the properties for the Accordion component.
type AccordionProps struct { type AccordionProps struct {
// Items is a slice of AccordionItem structs representing each item in the accordion. // Items contains the accordion sections
Items []AccordionItem Items []AccordionItem
// Class specifies additional CSS classes to apply to the accordion container. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Attributes allows passing additional HTML attributes to the accordion container element. // Attributes for additional HTML attributes and Alpine.js bindings
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Accordion renders an accordion component based on the provided props. // Accordion renders a collapsible content section component with expand/collapse functionality.
// It uses Alpine.js for interactivity and state management. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/accordion
//
// Usage:
//
// @components.Accordion(components.AccordionProps{
// Items: []components.AccordionItem{
// {
// ID: "item-1",
// Trigger: templ.Raw("Is it accessible?"),
// Content: templ.Raw("Yes. It adheres to the WAI-ARIA design pattern."),
// },
// {
// ID: "item-2",
// Trigger: templ.Raw("Is it styled?"),
// Content: templ.Raw("Yes. It comes with default styles that match the other components' aesthetic."),
// },
// },
// Class: "w-full sm:max-w-[70%]",
// Attributes: templ.Attributes{"data-testid": "my-accordion"},
// })
// //
// Props: // Props:
// - Items: A slice of AccordionItem structs, each representing an item in the accordion. // - Items: Array of accordion sections with ID, trigger and content
// - Class: Additional CSS classes to apply to the accordion container. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil // - Attributes: Additional HTML attributes (e.g. data-testid)
func Accordion(props AccordionProps) templ.Component { func Accordion(props AccordionProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -127,7 +103,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("toggleItem('" + item.ID + "')") templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("toggleItem('" + item.ID + "')")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 79, Col: 46} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 55, Col: 46}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -140,7 +116,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'") templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 81, Col: 57} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 57, Col: 57}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -165,7 +141,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'") templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 88, Col: 48} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/accordion.templ`, Line: 64, Col: 48}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -2,26 +2,26 @@ package components
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// AlertVariant represents the visual style of the alert. // AlertVariant defines the available alert styles
type AlertVariant string type AlertVariant string
// Constants for alert variants.
const ( const (
DefaultAlert AlertVariant = "default" // DefaultAlert shows standard informational styling
DefaultAlert AlertVariant = "default"
// DestructiveAlert shows error/warning styling
DestructiveAlert AlertVariant = "destructive" DestructiveAlert AlertVariant = "destructive"
) )
// AlertProps defines the properties for the Alert component.
type AlertProps struct { type AlertProps struct {
// Variant determines the visual style of the alert. // Variant controls the alert styling (default or destructive)
// Default: DefaultAlert
Variant AlertVariant Variant AlertVariant
// Class specifies additional CSS classes to apply to the alert.
// Default: "" (empty string) // Class adds custom CSS classes
Class string Class string
} }
// getAlertVariantClasses returns the CSS classes for the given alert variant. // getAlertVariantClasses maps variants to their CSS classes
func getAlertVariantClasses(variant AlertVariant) string { func getAlertVariantClasses(variant AlertVariant) string {
switch variant { switch variant {
case DestructiveAlert: case DestructiveAlert:
@ -31,21 +31,12 @@ func getAlertVariantClasses(variant AlertVariant) string {
} }
} }
// Alert renders an alert component based on the provided props and children. // Alert renders a notification box component for messages, warnings and errors.
// It can be customized with two visual styles: Default and Destructive. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/alert
// All content, including icons, should be passed in as children.
//
// Usage:
//
// @components.Alert(components.AlertProps{Variant: components.DestructiveAlert}) {
// @components.ExclamationTriangleIcon()
// @components.AlertTitle{"Error"}
// @components.AlertDescription{"Your session has expired. Please log in again."}
// }
// //
// Props: // Props:
// - Variant: The visual style of the alert (DefaultAlert or DestructiveAlert). Default: DefaultAlert // - Variant: Visual style (DefaultAlert or DestructiveAlert)
// - Class: Additional CSS classes to apply to the alert. Default: "" (empty string) // - Class: Additional CSS classes
templ Alert(props AlertProps) { templ Alert(props AlertProps) {
<div <div
class={ class={

View File

@ -10,26 +10,26 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// AlertVariant represents the visual style of the alert. // AlertVariant defines the available alert styles
type AlertVariant string type AlertVariant string
// Constants for alert variants.
const ( const (
DefaultAlert AlertVariant = "default" // DefaultAlert shows standard informational styling
DefaultAlert AlertVariant = "default"
// DestructiveAlert shows error/warning styling
DestructiveAlert AlertVariant = "destructive" DestructiveAlert AlertVariant = "destructive"
) )
// AlertProps defines the properties for the Alert component.
type AlertProps struct { type AlertProps struct {
// Variant determines the visual style of the alert. // Variant controls the alert styling (default or destructive)
// Default: DefaultAlert
Variant AlertVariant Variant AlertVariant
// Class specifies additional CSS classes to apply to the alert.
// Default: "" (empty string) // Class adds custom CSS classes
Class string Class string
} }
// getAlertVariantClasses returns the CSS classes for the given alert variant. // getAlertVariantClasses maps variants to their CSS classes
func getAlertVariantClasses(variant AlertVariant) string { func getAlertVariantClasses(variant AlertVariant) string {
switch variant { switch variant {
case DestructiveAlert: case DestructiveAlert:
@ -39,21 +39,12 @@ func getAlertVariantClasses(variant AlertVariant) string {
} }
} }
// Alert renders an alert component based on the provided props and children. // Alert renders a notification box component for messages, warnings and errors.
// It can be customized with two visual styles: Default and Destructive. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/alert
// All content, including icons, should be passed in as children.
//
// Usage:
//
// @components.Alert(components.AlertProps{Variant: components.DestructiveAlert}) {
// @components.ExclamationTriangleIcon()
// @components.AlertTitle{"Error"}
// @components.AlertDescription{"Your session has expired. Please log in again."}
// }
// //
// Props: // Props:
// - Variant: The visual style of the alert (DefaultAlert or DestructiveAlert). Default: DefaultAlert // - Variant: Visual style (DefaultAlert or DestructiveAlert)
// - Class: Additional CSS classes to apply to the alert. Default: "" (empty string) // - Class: Additional CSS classes
func Alert(props AlertProps) templ.Component { func Alert(props AlertProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context

View File

@ -6,36 +6,39 @@ import (
"strings" "strings"
) )
// AvatarSize represents the size of the avatar. // AvatarSize defines the available avatar dimensions
type AvatarSize string type AvatarSize string
const ( const (
AvatarSizeSmall AvatarSize = "small" // AvatarSizeSmall renders a small avatar (32x32px)
AvatarSizeSmall AvatarSize = "small"
// AvatarSizeMedium renders a medium avatar (48x48px)
AvatarSizeMedium AvatarSize = "medium" AvatarSizeMedium AvatarSize = "medium"
AvatarSizeLarge AvatarSize = "large"
// AvatarSizeLarge renders a large avatar (64x64px)
AvatarSizeLarge AvatarSize = "large"
) )
// AvatarProps defines the properties for the Avatar component.
type AvatarProps struct { type AvatarProps struct {
// ImageSrc is the URL of the avatar image. // ImageSrc is the URL for the avatar image
// If empty, initials will be used. // If empty, initials will be shown instead
ImageSrc string ImageSrc string
// Name is used to generate initials if ImageSrc is empty. // Name is used to generate initials when no image is provided
Name string Name string
// Size determines the size of the avatar. // Size controls the avatar dimensions (small, medium, large)
// Default: AvatarSizeMedium
Size AvatarSize Size AvatarSize
// Class specifies additional CSS classes to apply to the avatar. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the avatar element. // Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// getInitials generates initials from the given name. // AvatarInitials generates a 1-2 character initial from the given name
func AvatarInitials(name string) string { func AvatarInitials(name string) string {
parts := strings.Fields(name) parts := strings.Fields(name)
initials := "" initials := ""
@ -50,7 +53,7 @@ func AvatarInitials(name string) string {
return strings.ToUpper(initials) return strings.ToUpper(initials)
} }
// getSizeClasses returns the CSS classes for the given avatar size. // AvatarSizeClasses maps sizes to their corresponding CSS classes
func AvatarSizeClasses(size AvatarSize) string { func AvatarSizeClasses(size AvatarSize) string {
switch size { switch size {
case AvatarSizeSmall: case AvatarSizeSmall:
@ -62,24 +65,15 @@ func AvatarSizeClasses(size AvatarSize) string {
} }
} }
// Avatar renders an avatar component based on the provided props. // Avatar renders a circular image or initials for user representation.
// It displays an image if ImageSrc is provided, otherwise it shows initials. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/avatar
//
// Usage:
//
// @components.Avatar(components.AvatarProps{
// ImageSrc: "https://example.com/avatar.jpg",
// Name: "John Doe",
// Size: components.AvatarSizeMedium,
// Class: "border-2 border-blue-500",
// })
// //
// Props: // Props:
// - ImageSrc: The URL of the avatar image. Default: "" (empty string) // - ImageSrc: URL for the avatar image
// - Name: The name used to generate initials if ImageSrc is empty. Default: "" (empty string) // - Name: Text to generate initials from when no image is provided
// - Size: The size of the avatar (AvatarSizeSmall, AvatarSizeMedium, AvatarSizeLarge). Default: AvatarSizeMedium // - Size: Avatar dimensions (small, medium, large)
// - Class: Additional CSS classes to apply to the avatar. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the avatar element. Default: nil // - Attributes: Additional HTML attributes
templ Avatar(props AvatarProps) { templ Avatar(props AvatarProps) {
<div <div
class={ class={

View File

@ -14,36 +14,39 @@ import (
"strings" "strings"
) )
// AvatarSize represents the size of the avatar. // AvatarSize defines the available avatar dimensions
type AvatarSize string type AvatarSize string
const ( const (
AvatarSizeSmall AvatarSize = "small" // AvatarSizeSmall renders a small avatar (32x32px)
AvatarSizeSmall AvatarSize = "small"
// AvatarSizeMedium renders a medium avatar (48x48px)
AvatarSizeMedium AvatarSize = "medium" AvatarSizeMedium AvatarSize = "medium"
AvatarSizeLarge AvatarSize = "large"
// AvatarSizeLarge renders a large avatar (64x64px)
AvatarSizeLarge AvatarSize = "large"
) )
// AvatarProps defines the properties for the Avatar component.
type AvatarProps struct { type AvatarProps struct {
// ImageSrc is the URL of the avatar image. // ImageSrc is the URL for the avatar image
// If empty, initials will be used. // If empty, initials will be shown instead
ImageSrc string ImageSrc string
// Name is used to generate initials if ImageSrc is empty. // Name is used to generate initials when no image is provided
Name string Name string
// Size determines the size of the avatar. // Size controls the avatar dimensions (small, medium, large)
// Default: AvatarSizeMedium
Size AvatarSize Size AvatarSize
// Class specifies additional CSS classes to apply to the avatar. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the avatar element. // Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// getInitials generates initials from the given name. // AvatarInitials generates a 1-2 character initial from the given name
func AvatarInitials(name string) string { func AvatarInitials(name string) string {
parts := strings.Fields(name) parts := strings.Fields(name)
initials := "" initials := ""
@ -58,7 +61,7 @@ func AvatarInitials(name string) string {
return strings.ToUpper(initials) return strings.ToUpper(initials)
} }
// getSizeClasses returns the CSS classes for the given avatar size. // AvatarSizeClasses maps sizes to their corresponding CSS classes
func AvatarSizeClasses(size AvatarSize) string { func AvatarSizeClasses(size AvatarSize) string {
switch size { switch size {
case AvatarSizeSmall: case AvatarSizeSmall:
@ -70,24 +73,15 @@ func AvatarSizeClasses(size AvatarSize) string {
} }
} }
// Avatar renders an avatar component based on the provided props. // Avatar renders a circular image or initials for user representation.
// It displays an image if ImageSrc is provided, otherwise it shows initials. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/avatar
//
// Usage:
//
// @components.Avatar(components.AvatarProps{
// ImageSrc: "https://example.com/avatar.jpg",
// Name: "John Doe",
// Size: components.AvatarSizeMedium,
// Class: "border-2 border-blue-500",
// })
// //
// Props: // Props:
// - ImageSrc: The URL of the avatar image. Default: "" (empty string) // - ImageSrc: URL for the avatar image
// - Name: The name used to generate initials if ImageSrc is empty. Default: "" (empty string) // - Name: Text to generate initials from when no image is provided
// - Size: The size of the avatar (AvatarSizeSmall, AvatarSizeMedium, AvatarSizeLarge). Default: AvatarSizeMedium // - Size: Avatar dimensions (small, medium, large)
// - Class: Additional CSS classes to apply to the avatar. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the avatar element. Default: nil // - Attributes: Additional HTML attributes
func Avatar(props AvatarProps) templ.Component { func Avatar(props AvatarProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -153,7 +147,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ImageSrc) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ImageSrc)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 96, Col: 24} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 90, Col: 24}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -166,7 +160,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s's avatar", props.Name)) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s's avatar", props.Name))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 97, Col: 48} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 91, Col: 48}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -184,7 +178,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(AvatarInitials(props.Name)) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(AvatarInitials(props.Name))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 102, Col: 32} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/avatar.templ`, Line: 96, Col: 32}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -5,80 +5,67 @@ import (
"strings" "strings"
) )
// ButtonVariant represents the visual style of the button. // ButtonVariant defines the available button styles
type ButtonVariant string type ButtonVariant string
// ButtonSize represents the size of the button. // ButtonSize defines the available button dimensions
type ButtonSize string type ButtonSize string
// Constants for button variants and sizes.
const ( const (
Default ButtonVariant = "default" // Button style variants
Destructive ButtonVariant = "destructive" Default ButtonVariant = "default" // Primary action button
Outline ButtonVariant = "outline" Destructive ButtonVariant = "destructive" // Dangerous/warning action
Secondary ButtonVariant = "secondary" Outline ButtonVariant = "outline" // Bordered button
Ghost ButtonVariant = "ghost" Secondary ButtonVariant = "secondary" // Less prominent action
Link ButtonVariant = "link" Ghost ButtonVariant = "ghost" // Minimal styling
Link ButtonVariant = "link" // Appears as a text link
Md ButtonSize = "md" // Button sizes
Sm ButtonSize = "sm" Md ButtonSize = "md" // Standard size
Lg ButtonSize = "lg" Sm ButtonSize = "sm" // Compact size
ButtonIcon ButtonSize = "icon" Lg ButtonSize = "lg" // Large size
ButtonIcon ButtonSize = "icon" // Square icon button
) )
// Button defines the properties for the Button component.
type ButtonProps struct { type ButtonProps struct {
// Class specifies additional CSS classes to apply to the button. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Text is the content of the button. // Text contains the button label
// Default: "" (empty string)
Text string Text string
// Variant determines the visual style of the button. // Variant controls the button styling
// Default: Default
Variant ButtonVariant Variant ButtonVariant
// Size sets the size of the button. // Size controls button dimensions
// Default: Md
Size ButtonSize Size ButtonSize
// FullWidth determines whether the button should take up the full width of its container. // FullWidth makes button expand to container width
// Default: false
FullWidth bool FullWidth bool
// Href, if provided, renders the button as an anchor tag with this URL. // Href turns the button into a link
// Default: "" (empty string)
Href string Href string
// Target specifies the target attribute for the anchor tag (only used when Href is provided). // Target controls link opening behavior
// Default: "" (empty string)
Target string Target string
// Disabled can be either a bool or a string. // Disabled controls interactive state (bool or JS expression)
// If bool (Go), it directly controls the disabled state.
// If string, it's treated as a JavaScript expression for dynamic disabling.
Disabled any Disabled any
// Type specifies the type of the button. Default: "button" // Type sets the button type attribute
// Default: "" (empty string)
Type string Type string
// Attributes allows passing additional HTML attributes to the button or anchor element. // Attributes for additional HTML attributes
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
// IconLeft specifies an icon component to be displayed on the left side of the button text. // IconLeft displays an icon before text
// Default: nil
IconLeft templ.Component IconLeft templ.Component
// IconRight specifies an icon component to be displayed on the right side of the button text. // IconRight displays an icon after text
// Default: nil
IconRight templ.Component IconRight templ.Component
} }
// Variant als Methode // variantClasses maps variants to their CSS classes
func (b ButtonProps) variantClasses() string { func (b ButtonProps) variantClasses() string {
switch b.Variant { switch b.Variant {
case Destructive: case Destructive:
@ -96,7 +83,7 @@ func (b ButtonProps) variantClasses() string {
} }
} }
// Size als Methode // sizeClasses maps sizes to their CSS classes
func (b ButtonProps) sizeClasses() string { func (b ButtonProps) sizeClasses() string {
switch b.Size { switch b.Size {
case Sm: case Sm:
@ -110,6 +97,7 @@ func (b ButtonProps) sizeClasses() string {
} }
} }
// modifierClasses generates additional utility classes
func (b ButtonProps) modifierClasses() string { func (b ButtonProps) modifierClasses() string {
classes := []string{} classes := []string{}
if b.FullWidth { if b.FullWidth {
@ -118,37 +106,22 @@ func (b ButtonProps) modifierClasses() string {
return strings.Join(classes, " ") return strings.Join(classes, " ")
} }
// Button renders a button or anchor component based on the provided props. // Button renders an interactive button or link component with consistent styling.
// It can be customized with various visual styles, sizes, and behaviors. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/button
//
// Usage:
//
// @components.Button(components.ButtonProps{
// Text: "Click me",
// Variant: components.Primary,
// Size: components.Md,
// FullWidth: false,
// IconLeft: components.Icon(components.IconProps{Name: "user"}),
// IconRight: components.Icon(components.IconProps{Name: "arrow-right"}),
// Attributes: templ.Attributes{
// "aria-label": "Click this button",
// "data-testid": "main-button",
// },
// })
// //
// Props: // Props:
// - Class: Additional CSS classes to apply to the button. Default: "" (empty string) // - Class: Additional CSS classes
// - Text: The text content of the button. Default: "" (empty string) // - Text: Button label text
// - Variant: The visual style of the button (e.g., Default, Destructive, Outline). Default: Default // - Variant: Visual style (default, destructive, outline, etc)
// - Size: The size of the button (Md, Sm, Lg, Icon). Default: Md // - Size: Button dimensions (sm, md, lg, icon)
// - FullWidth: Whether the button should take up the full width of its container. Default: false // - FullWidth: Expand to fill container
// - Href: If provided, renders the button as an anchor tag with this URL. Default: "" (empty string) // - Href: Optional URL for link buttons
// - Target: The target attribute for the anchor tag (only used when Href is provided). Default: "" (empty string) // - Target: Link target attribute
// - Disabled: Can be either a bool or a string. If bool (Go), it directly controls the disabled state. If string, it's treated as a JavaScript expression for dynamic disabling. Default: nil // - Disabled: Interactivity state
// - Type: The type of the button. Default: "button" // - Type: Button type attribute
// - Attributes: Additional HTML attributes to apply to the button or anchor element. Default: nil // - Attributes: Additional HTML attributes
// - IconLeft: An icon component to be displayed on the left side of the button text. Default: nil // - IconLeft: Icon component before text
// - IconRight: An icon component to be displayed on the right side of the button text. Default: nil // - IconRight: Icon component after text
templ Button(props ButtonProps) { templ Button(props ButtonProps) {
if props.Href != "" { if props.Href != "" {
<a <a
@ -209,7 +182,7 @@ templ Button(props ButtonProps) {
} }
} }
// renderButtonContent renders the content of the button, including icons and text // renderButtonContent arranges button text and icons
templ renderButtonContent(props ButtonProps) { templ renderButtonContent(props ButtonProps) {
<span class="flex gap-2 items-center"> <span class="flex gap-2 items-center">
if props.IconLeft != nil { if props.IconLeft != nil {

View File

@ -13,80 +13,67 @@ import (
"strings" "strings"
) )
// ButtonVariant represents the visual style of the button. // ButtonVariant defines the available button styles
type ButtonVariant string type ButtonVariant string
// ButtonSize represents the size of the button. // ButtonSize defines the available button dimensions
type ButtonSize string type ButtonSize string
// Constants for button variants and sizes.
const ( const (
Default ButtonVariant = "default" // Button style variants
Destructive ButtonVariant = "destructive" Default ButtonVariant = "default" // Primary action button
Outline ButtonVariant = "outline" Destructive ButtonVariant = "destructive" // Dangerous/warning action
Secondary ButtonVariant = "secondary" Outline ButtonVariant = "outline" // Bordered button
Ghost ButtonVariant = "ghost" Secondary ButtonVariant = "secondary" // Less prominent action
Link ButtonVariant = "link" Ghost ButtonVariant = "ghost" // Minimal styling
Link ButtonVariant = "link" // Appears as a text link
Md ButtonSize = "md" // Button sizes
Sm ButtonSize = "sm" Md ButtonSize = "md" // Standard size
Lg ButtonSize = "lg" Sm ButtonSize = "sm" // Compact size
ButtonIcon ButtonSize = "icon" Lg ButtonSize = "lg" // Large size
ButtonIcon ButtonSize = "icon" // Square icon button
) )
// Button defines the properties for the Button component.
type ButtonProps struct { type ButtonProps struct {
// Class specifies additional CSS classes to apply to the button. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Text is the content of the button. // Text contains the button label
// Default: "" (empty string)
Text string Text string
// Variant determines the visual style of the button. // Variant controls the button styling
// Default: Default
Variant ButtonVariant Variant ButtonVariant
// Size sets the size of the button. // Size controls button dimensions
// Default: Md
Size ButtonSize Size ButtonSize
// FullWidth determines whether the button should take up the full width of its container. // FullWidth makes button expand to container width
// Default: false
FullWidth bool FullWidth bool
// Href, if provided, renders the button as an anchor tag with this URL. // Href turns the button into a link
// Default: "" (empty string)
Href string Href string
// Target specifies the target attribute for the anchor tag (only used when Href is provided). // Target controls link opening behavior
// Default: "" (empty string)
Target string Target string
// Disabled can be either a bool or a string. // Disabled controls interactive state (bool or JS expression)
// If bool (Go), it directly controls the disabled state.
// If string, it's treated as a JavaScript expression for dynamic disabling.
Disabled any Disabled any
// Type specifies the type of the button. Default: "button" // Type sets the button type attribute
// Default: "" (empty string)
Type string Type string
// Attributes allows passing additional HTML attributes to the button or anchor element. // Attributes for additional HTML attributes
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
// IconLeft specifies an icon component to be displayed on the left side of the button text. // IconLeft displays an icon before text
// Default: nil
IconLeft templ.Component IconLeft templ.Component
// IconRight specifies an icon component to be displayed on the right side of the button text. // IconRight displays an icon after text
// Default: nil
IconRight templ.Component IconRight templ.Component
} }
// Variant als Methode // variantClasses maps variants to their CSS classes
func (b ButtonProps) variantClasses() string { func (b ButtonProps) variantClasses() string {
switch b.Variant { switch b.Variant {
case Destructive: case Destructive:
@ -104,7 +91,7 @@ func (b ButtonProps) variantClasses() string {
} }
} }
// Size als Methode // sizeClasses maps sizes to their CSS classes
func (b ButtonProps) sizeClasses() string { func (b ButtonProps) sizeClasses() string {
switch b.Size { switch b.Size {
case Sm: case Sm:
@ -118,6 +105,7 @@ func (b ButtonProps) sizeClasses() string {
} }
} }
// modifierClasses generates additional utility classes
func (b ButtonProps) modifierClasses() string { func (b ButtonProps) modifierClasses() string {
classes := []string{} classes := []string{}
if b.FullWidth { if b.FullWidth {
@ -126,37 +114,22 @@ func (b ButtonProps) modifierClasses() string {
return strings.Join(classes, " ") return strings.Join(classes, " ")
} }
// Button renders a button or anchor component based on the provided props. // Button renders an interactive button or link component with consistent styling.
// It can be customized with various visual styles, sizes, and behaviors. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/button
//
// Usage:
//
// @components.Button(components.ButtonProps{
// Text: "Click me",
// Variant: components.Primary,
// Size: components.Md,
// FullWidth: false,
// IconLeft: components.Icon(components.IconProps{Name: "user"}),
// IconRight: components.Icon(components.IconProps{Name: "arrow-right"}),
// Attributes: templ.Attributes{
// "aria-label": "Click this button",
// "data-testid": "main-button",
// },
// })
// //
// Props: // Props:
// - Class: Additional CSS classes to apply to the button. Default: "" (empty string) // - Class: Additional CSS classes
// - Text: The text content of the button. Default: "" (empty string) // - Text: Button label text
// - Variant: The visual style of the button (e.g., Default, Destructive, Outline). Default: Default // - Variant: Visual style (default, destructive, outline, etc)
// - Size: The size of the button (Md, Sm, Lg, Icon). Default: Md // - Size: Button dimensions (sm, md, lg, icon)
// - FullWidth: Whether the button should take up the full width of its container. Default: false // - FullWidth: Expand to fill container
// - Href: If provided, renders the button as an anchor tag with this URL. Default: "" (empty string) // - Href: Optional URL for link buttons
// - Target: The target attribute for the anchor tag (only used when Href is provided). Default: "" (empty string) // - Target: Link target attribute
// - Disabled: Can be either a bool or a string. If bool (Go), it directly controls the disabled state. If string, it's treated as a JavaScript expression for dynamic disabling. Default: nil // - Disabled: Interactivity state
// - Type: The type of the button. Default: "button" // - Type: Button type attribute
// - Attributes: Additional HTML attributes to apply to the button or anchor element. Default: nil // - Attributes: Additional HTML attributes
// - IconLeft: An icon component to be displayed on the left side of the button text. Default: nil // - IconLeft: Icon component before text
// - IconRight: An icon component to be displayed on the right side of the button text. Default: nil // - IconRight: Icon component after text
func Button(props ButtonProps) templ.Component { func Button(props ButtonProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -209,7 +182,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Target) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Target)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 156, Col: 24} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 129, Col: 24}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -247,7 +220,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 172, Col: 33} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 145, Col: 33}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -320,7 +293,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var9 string var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Type) templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Type)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 194, Col: 21} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 167, Col: 21}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -348,7 +321,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var10 string var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr) templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 201, Col: 28} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 174, Col: 28}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -385,7 +358,7 @@ func Button(props ButtonProps) templ.Component {
}) })
} }
// renderButtonContent renders the content of the button, including icons and text // renderButtonContent arranges button text and icons
func renderButtonContent(props ButtonProps) templ.Component { func renderButtonContent(props ButtonProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -420,7 +393,7 @@ func renderButtonContent(props ButtonProps) templ.Component {
var templ_7745c5c3_Var12 string var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Text) templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Text)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 218, Col: 14} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/button.templ`, Line: 191, Col: 14}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -2,32 +2,20 @@ package components
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// CardProps defines the properties for the Card component.
type CardProps struct { type CardProps struct {
// Class specifies additional CSS classes to apply to the card. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Attributes allows passing additional HTML attributes to the card element. // Attributes for additional HTML attributes
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Card renders a card component based on the provided props. // Card renders a container component with consistent styling and structure.
// It can be customized with additional classes and attributes. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/card
//
// Usage:
//
// @components.Card(components.CardProps{
// Class: "custom-card",
// Attributes: templ.Attributes{"data-testid": "my-card"},
// }) {
// // Card content goes here
// }
// //
// Props: // Props:
// - Class: Additional CSS classes to apply to the card. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the card element. Default: nil // - Attributes: Additional HTML attributes
templ Card(props CardProps) { templ Card(props CardProps) {
<div <div
class={ utils.TwMerge("rounded-lg border bg-card text-card-foreground shadow-sm", props.Class) } class={ utils.TwMerge("rounded-lg border bg-card text-card-foreground shadow-sm", props.Class) }
@ -37,66 +25,40 @@ templ Card(props CardProps) {
</div> </div>
} }
// CardHeader renders the header section of a card. // CardHeader renders the top section of the card
// // Typically contains title and description
// Usage:
//
// @components.CardHeader() {
// @components.CardTitle() { Card Title }
// @components.CardDescription() { Card description goes here }
// }
templ CardHeader() { templ CardHeader() {
<div class="flex flex-col space-y-1.5 p-6"> <div class="flex flex-col space-y-1.5 p-6">
{ children... } { children... }
</div> </div>
} }
// CardTitle renders the title of a card. // CardTitle renders the card's main heading
// // Uses h3 with consistent styling
// Usage:
//
// @components.CardTitle() {
// My Card Title
// }
templ CardTitle() { templ CardTitle() {
<h3 class="font-semibold leading-none tracking-tight"> <h3 class="font-semibold leading-none tracking-tight">
{ children... } { children... }
</h3> </h3>
} }
// CardDescription renders the description of a card. // CardDescription renders secondary text below the title
// // Uses muted styling for visual hierarchy
// Usage:
//
// @components.CardDescription() {
// This is a detailed description of the card's content.
// }
templ CardDescription() { templ CardDescription() {
<p class="text-sm text-muted-foreground"> <p class="text-sm text-muted-foreground">
{ children... } { children... }
</p> </p>
} }
// CardContent renders the main content section of a card. // CardContent renders the main card body section
// // Contains the primary content area
// Usage:
//
// @components.CardContent() {
// // Main card content goes here
// }
templ CardContent() { templ CardContent() {
<div class="p-6 pt-0"> <div class="p-6 pt-0">
{ children... } { children... }
</div> </div>
} }
// CardFooter renders the footer section of a card. // CardFooter renders the bottom section of the card
// // Typically contains actions or summary information
// Usage:
//
// @components.CardFooter() {
// @components.Button(components.ButtonProps{Text: "Submit"})
// }
templ CardFooter() { templ CardFooter() {
<div class="flex items-center p-6 pt-0"> <div class="flex items-center p-6 pt-0">
{ children... } { children... }

View File

@ -10,32 +10,20 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// CardProps defines the properties for the Card component.
type CardProps struct { type CardProps struct {
// Class specifies additional CSS classes to apply to the card. // Class adds custom CSS classes
// Default: "" (empty string)
Class string Class string
// Attributes allows passing additional HTML attributes to the card element. // Attributes for additional HTML attributes
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Card renders a card component based on the provided props. // Card renders a container component with consistent styling and structure.
// It can be customized with additional classes and attributes. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/card
//
// Usage:
//
// @components.Card(components.CardProps{
// Class: "custom-card",
// Attributes: templ.Attributes{"data-testid": "my-card"},
// }) {
// // Card content goes here
// }
// //
// Props: // Props:
// - Class: Additional CSS classes to apply to the card. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the card element. Default: nil // - Attributes: Additional HTML attributes
func Card(props CardProps) templ.Component { func Card(props CardProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -99,14 +87,8 @@ func Card(props CardProps) templ.Component {
}) })
} }
// CardHeader renders the header section of a card. // CardHeader renders the top section of the card
// // Typically contains title and description
// Usage:
//
// @components.CardHeader() {
// @components.CardTitle() { Card Title }
// @components.CardDescription() { Card description goes here }
// }
func CardHeader() templ.Component { func CardHeader() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -144,13 +126,8 @@ func CardHeader() templ.Component {
}) })
} }
// CardTitle renders the title of a card. // CardTitle renders the card's main heading
// // Uses h3 with consistent styling
// Usage:
//
// @components.CardTitle() {
// My Card Title
// }
func CardTitle() templ.Component { func CardTitle() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -188,13 +165,8 @@ func CardTitle() templ.Component {
}) })
} }
// CardDescription renders the description of a card. // CardDescription renders secondary text below the title
// // Uses muted styling for visual hierarchy
// Usage:
//
// @components.CardDescription() {
// This is a detailed description of the card's content.
// }
func CardDescription() templ.Component { func CardDescription() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -232,13 +204,8 @@ func CardDescription() templ.Component {
}) })
} }
// CardContent renders the main content section of a card. // CardContent renders the main card body section
// // Contains the primary content area
// Usage:
//
// @components.CardContent() {
// // Main card content goes here
// }
func CardContent() templ.Component { func CardContent() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -276,13 +243,8 @@ func CardContent() templ.Component {
}) })
} }
// CardFooter renders the footer section of a card. // CardFooter renders the bottom section of the card
// // Typically contains actions or summary information
// Usage:
//
// @components.CardFooter() {
// @components.Button(components.ButtonProps{Text: "Submit"})
// }
func CardFooter() templ.Component { func CardFooter() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context

View File

@ -5,99 +5,74 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// CheckboxProps defines the properties for the Checkbox component.
type CheckboxProps struct { type CheckboxProps struct {
// ID is the unique identifier for the checkbox input. // ID uniquely identifies the checkbox input
ID string ID string
// Name is the name attribute for the checkbox input. // Name sets the form field name
Name string Name string
// Value is the value attribute for the checkbox input. // Value sets the checkbox value
Value string Value string
// Label is the text label associated with the checkbox. // Label displays text next to checkbox
// If empty, no label will be rendered. // Empty string hides the label
Label string Label string
// Checked is a JavaScript expression for the checked state // Class adds custom CSS classes
// Example: "true", "isSubscribed", "5+5===10"
Checked string
// Disabled is a JavaScript expression for the disabled state
// Example: "true", "isLoading", "!isEnabled"
Disabled string
// Class specifies additional CSS classes for the container
Class string Class string
// Attributes allows passing additional HTML attributes // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Checkbox renders a customizable checkbox component with an associated label. // Checkbox renders a styled checkbox input with optional label.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
// Usage:
//
// @components.Checkbox(components.CheckboxProps{
// ID: "terms",
// Name: "accept_terms",
// Value: "accepted",
// Label: "I accept the terms and conditions",
// Checked: "true",
// Disabled: "isSubmitting",
// Class: "mt-4",
// Attributes: templ.Attributes{"data-testid": "terms-checkbox"},
// })
// //
// Props: // Props:
// - ID: The unique identifier for the checkbox input. Required. // - ID: Unique identifier for the input
// - Name: The name attribute for the checkbox input. Required. // - Name: Form field name
// - Value: The value attribute for the checkbox input. Required. // - Value: Checkbox value
// - Label: The text label associated with the checkbox. Optional. // - Label: Optional text label
// - Checked: Determines the checked state. Can be a bool or a string for dynamic binding. Optional. // - Class: Additional CSS classes
// - Disabled: Determines the disabled state. Can be a bool or a string for dynamic binding. Optional. // - Attributes: Additional HTML attributes
// - Class: Additional CSS classes to apply to the checkbox container. Optional.
// - Attributes: Additional HTML attributes to apply to the checkbox input element. Optional.
templ Checkbox(props CheckboxProps) { templ Checkbox(props CheckboxProps) {
<div x-data="{ checked: false }" class={ utils.TwMerge("flex items-center space-x-2", props.Class) }> <label
<div class="relative"> 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 <input
type="checkbox"
id={ props.ID } id={ props.ID }
name={ props.Name } name={ props.Name }
value={ props.Value } value={ props.Value }
x-ref="checkbox" type="checkbox"
x-model="checked" class="before:content[''] peer relative size-4 cursor-pointer appearance-none overflow-hidden
if props.Checked != "" { rounded-sm border border-2 border-primary
x-init={ "checked = " + props.Checked } bg-background before:absolute before:inset-0
} checked:before:bg-primary
if props.Disabled != "" { focus:outline focus:outline-2 focus:outline-offset-2
:disabled={ props.Disabled } focus:outline-ring checked:focus:outline-primary
} active:outline-offset-0
class="absolute w-full h-full opacity-0 z-10 cursor-pointer peer" disabled:cursor-not-allowed
transition-colors"
{ props.Attributes... } { props.Attributes... }
/> />
<div <div
class="h-4 w-4 rounded-sm border border-primary ring-offset-background class="pointer-events-none invisible absolute left-1/2 top-1/2 size-3
peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 -translate-x-1/2 -translate-y-1/2 text-primary-foreground
peer-disabled:cursor-not-allowed peer-disabled:opacity-50 peer-checked:visible"
flex items-center justify-center
bg-background peer-checked:bg-primary transition-colors"
> >
<div x-show="checked" class="text-primary-foreground"> @icons.Check(icons.IconProps{Size: "12"})
@icons.Check(icons.IconProps{Size: "12"})
</div>
</div> </div>
</div> </div>
if props.Label != "" { if props.Label != "" {
<label <span>{ props.Label }</span>
for={ props.ID }
class="text-sm font-medium leading-none cursor-pointer select-none"
:class="{ 'text-muted-foreground': !checked, 'text-foreground': checked }"
>
{ props.Label }
</label>
} }
</div> </label>
} }

View File

@ -13,60 +13,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// CheckboxProps defines the properties for the Checkbox component.
type CheckboxProps struct { type CheckboxProps struct {
// ID is the unique identifier for the checkbox input. // ID uniquely identifies the checkbox input
ID string ID string
// Name is the name attribute for the checkbox input. // Name sets the form field name
Name string Name string
// Value is the value attribute for the checkbox input. // Value sets the checkbox value
Value string Value string
// Label is the text label associated with the checkbox. // Label displays text next to checkbox
// If empty, no label will be rendered. // Empty string hides the label
Label string Label string
// Checked is a JavaScript expression for the checked state // Class adds custom CSS classes
// Example: "true", "isSubscribed", "5+5===10"
Checked string
// Disabled is a JavaScript expression for the disabled state
// Example: "true", "isLoading", "!isEnabled"
Disabled string
// Class specifies additional CSS classes for the container
Class string Class string
// Attributes allows passing additional HTML attributes // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Checkbox renders a customizable checkbox component with an associated label. // Checkbox renders a styled checkbox input with optional label.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
// Usage:
//
// @components.Checkbox(components.CheckboxProps{
// ID: "terms",
// Name: "accept_terms",
// Value: "accepted",
// Label: "I accept the terms and conditions",
// Checked: "true",
// Disabled: "isSubmitting",
// Class: "mt-4",
// Attributes: templ.Attributes{"data-testid": "terms-checkbox"},
// })
// //
// Props: // Props:
// - ID: The unique identifier for the checkbox input. Required. // - ID: Unique identifier for the input
// - Name: The name attribute for the checkbox input. Required. // - Name: Form field name
// - Value: The value attribute for the checkbox input. Required. // - Value: Checkbox value
// - Label: The text label associated with the checkbox. Optional. // - Label: Optional text label
// - Checked: Determines the checked state. Can be a bool or a string for dynamic binding. Optional. // - Class: Additional CSS classes
// - Disabled: Determines the disabled state. Can be a bool or a string for dynamic binding. Optional. // - Attributes: Additional HTML attributes
// - Class: Additional CSS classes to apply to the checkbox container. Optional.
// - Attributes: Additional HTML attributes to apply to the checkbox input element. Optional.
func Checkbox(props CheckboxProps) templ.Component { func Checkbox(props CheckboxProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -88,47 +65,65 @@ func Checkbox(props CheckboxProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent templ_7745c5c3_Var1 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{utils.TwMerge("flex items-center space-x-2", props.Class)} 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,
)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{ checked: false }\" class=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String()) templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { 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: 41, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"relative\"><input type=\"checkbox\" id=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 67, Col: 17} 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_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"relative flex items-center\"><input id=\"")
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: 51, 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("\" name=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 68, Col: 21} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 52, Col: 21}
} }
_, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -136,58 +131,16 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var7 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value) templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 69, Col: 23} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 53, Col: 23}
} }
_, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-ref=\"checkbox\" x-model=\"checked\"") _, 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\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Checked != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" x-init=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("checked = " + props.Checked)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 73, Col: 42}
}
_, 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
}
}
if props.Disabled != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" :disabled=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Disabled)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 76, Col: 31}
}
_, 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
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" class=\"absolute w-full h-full opacity-0 z-10 cursor-pointer peer\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -195,7 +148,7 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("><div class=\"h-4 w-4 rounded-sm border border-primary ring-offset-background \n peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 \n peer-disabled:cursor-not-allowed peer-disabled:opacity-50\n flex items-center justify-center\n bg-background peer-checked:bg-primary transition-colors\"><div x-show=\"checked\" class=\"text-primary-foreground\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("><div class=\"pointer-events-none invisible absolute left-1/2 top-1/2 size-3 \n -translate-x-1/2 -translate-y-1/2 text-primary-foreground \n peer-checked:visible\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -203,43 +156,30 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
if props.Label != "" { if props.Label != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var9 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 95, Col: 18} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 75, Col: 22}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"text-sm font-medium leading-none cursor-pointer select-none\" :class=\"{ &#39;text-muted-foreground&#39;: !checked, &#39;text-foreground&#39;: checked }\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, 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: 99, Col: 17}
}
_, 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("</label>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -5,49 +5,43 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// DatepickerProps defines the properties for the Datepicker component.
type DatepickerProps struct { type DatepickerProps struct {
// ID is the unique identifier for the datepicker input. // ID uniquely identifies the datepicker input
ID string ID string
// Name is the name attribute for the datepicker input. // Name sets the form field name
Name string Name string
// Placeholder is the placeholder text for the datepicker input. // Placeholder shows helper text when empty
Placeholder string Placeholder string
// Format specifies the date format to use. Options: "M d, Y", "MM-DD-YYYY", "DD-MM-YYYY", "YYYY-MM-DD", "D d M, Y" // Format controls date string presentation
// Default: "M d, Y" // Supported formats:
// - "M d, Y" (Jan 1, 2024)
// - "MM-DD-YYYY" (01-01-2024)
// - "DD-MM-YYYY" (01-01-2024)
// - "YYYY-MM-DD" (2024-01-01)
// - "D d M, Y" (Mon 1 Jan, 2024)
Format string Format string
// Class specifies additional CSS classes to apply to the datepicker container. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the datepicker input element. // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Datepicker renders an enhanced datepicker component with an input field and a calendar view. // Datepicker renders a calendar input component with popup date selection.
// It uses Alpine.js for interactivity and provides various formatting options and improved navigation. // Uses Alpine.js for interactions and supports dark mode via Tailwind.
// This version supports dark mode using Tailwind CSS variables. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/datepicker
//
// Usage:
//
// @components.Datepicker(components.DatepickerProps{
// ID: "my-datepicker",
// Name: "selected-date",
// Placeholder: "Select a date",
// Format: "YYYY-MM-DD",
// Class: "w-full",
// })
// //
// Props: // Props:
// - ID: The unique identifier for the datepicker input. Default: "" (empty string) // - ID: Unique identifier for the input
// - Name: The name attribute for the datepicker input. Default: "" (empty string) // - Name: Form field name
// - Placeholder: The placeholder text for the datepicker input. Default: "" (empty string) // - Placeholder: Helper text when empty
// - Format: The date format to use. Default: "M d, Y" // - Format: Date display format
// - Class: Additional CSS classes to apply to the datepicker container. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the datepicker input element. Default: nil // - Attributes: Additional HTML attributes
templ Datepicker(props DatepickerProps) { templ Datepicker(props DatepickerProps) {
<div <div
data-date-format={ props.Format } data-date-format={ props.Format }
@ -174,7 +168,7 @@ templ Datepicker(props DatepickerProps) {
id={ props.ID } id={ props.ID }
name={ props.Name } name={ props.Name }
placeholder={ props.Placeholder } placeholder={ props.Placeholder }
x-model="datePickerValue" x-modelable="datePickerValue"
@click="toggleDatePicker()" @click="toggleDatePicker()"
x-on:keydown.escape="datePickerOpen = false" x-on:keydown.escape="datePickerOpen = false"
x-ref="datePickerInput" x-ref="datePickerInput"

View File

@ -13,49 +13,43 @@ import (
"github.com/axzilla/goilerplate/pkg/utils" "github.com/axzilla/goilerplate/pkg/utils"
) )
// DatepickerProps defines the properties for the Datepicker component.
type DatepickerProps struct { type DatepickerProps struct {
// ID is the unique identifier for the datepicker input. // ID uniquely identifies the datepicker input
ID string ID string
// Name is the name attribute for the datepicker input. // Name sets the form field name
Name string Name string
// Placeholder is the placeholder text for the datepicker input. // Placeholder shows helper text when empty
Placeholder string Placeholder string
// Format specifies the date format to use. Options: "M d, Y", "MM-DD-YYYY", "DD-MM-YYYY", "YYYY-MM-DD", "D d M, Y" // Format controls date string presentation
// Default: "M d, Y" // Supported formats:
// - "M d, Y" (Jan 1, 2024)
// - "MM-DD-YYYY" (01-01-2024)
// - "DD-MM-YYYY" (01-01-2024)
// - "YYYY-MM-DD" (2024-01-01)
// - "D d M, Y" (Mon 1 Jan, 2024)
Format string Format string
// Class specifies additional CSS classes to apply to the datepicker container. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the datepicker input element. // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Datepicker renders an enhanced datepicker component with an input field and a calendar view. // Datepicker renders a calendar input component with popup date selection.
// It uses Alpine.js for interactivity and provides various formatting options and improved navigation. // Uses Alpine.js for interactions and supports dark mode via Tailwind.
// This version supports dark mode using Tailwind CSS variables. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/datepicker
//
// Usage:
//
// @components.Datepicker(components.DatepickerProps{
// ID: "my-datepicker",
// Name: "selected-date",
// Placeholder: "Select a date",
// Format: "YYYY-MM-DD",
// Class: "w-full",
// })
// //
// Props: // Props:
// - ID: The unique identifier for the datepicker input. Default: "" (empty string) // - ID: Unique identifier for the input
// - Name: The name attribute for the datepicker input. Default: "" (empty string) // - Name: Form field name
// - Placeholder: The placeholder text for the datepicker input. Default: "" (empty string) // - Placeholder: Helper text when empty
// - Format: The date format to use. Default: "M d, Y" // - Format: Date display format
// - Class: Additional CSS classes to apply to the datepicker container. Default: "" (empty string) // - Class: Additional CSS classes
// - Attributes: Additional HTML attributes to apply to the datepicker input element. Default: nil // - Attributes: Additional HTML attributes
func Datepicker(props DatepickerProps) templ.Component { func Datepicker(props DatepickerProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -89,7 +83,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Format) templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Format)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 53, Col: 33} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 47, Col: 33}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -115,7 +109,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 174, Col: 17} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 168, Col: 17}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -128,7 +122,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 175, Col: 21} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 169, Col: 21}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -141,13 +135,13 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var7 string var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder) templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 176, Col: 35} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 170, Col: 35}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-model=\"datePickerValue\" @click=\"toggleDatePicker()\" x-on:keydown.escape=\"datePickerOpen = false\" x-ref=\"datePickerInput\" class=\"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\" readonly") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-modelable=\"datePickerValue\" @click=\"toggleDatePicker()\" x-on:keydown.escape=\"datePickerOpen = false\" x-ref=\"datePickerInput\" class=\"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\" readonly")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -7,29 +7,50 @@ import (
"strings" "strings"
) )
// DropdownMenuItem represents an item in the dropdown menu
type DropdownMenuItem struct { type DropdownMenuItem struct {
Label string // The text to display for the menu item // Label displays text for the menu item
Value string // The value associated with the menu item (for non-link items) Label string
Href string // The URL to navigate to if the item is a link
Target string // The target attribute for link items (e.g., "_blank" for new tab) // Value for non-link menu items
IconLeft templ.Component // An optional icon component to display on the left side of the item Value string
IconRight templ.Component // An optional icon component to display on the right side of the item
SubItems []DropdownMenuItem // A slice of DropdownMenuItems for nested submenus // Href makes item a navigation link
Disabled bool // Whether the item is disabled or not Href string
// Attributes allows passing additional HTML attributes to the accordion container element.
// Default: nil // Target controls link opening behavior
Target string
// IconLeft displays icon before label
IconLeft templ.Component
// IconRight displays icon after label
IconRight templ.Component
// SubItems creates nested submenu
SubItems []DropdownMenuItem
// Disabled controls interactive state
Disabled bool
// Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// DropdownMenuProps defines the properties for the DropdownMenu component
type DropdownMenuProps struct { type DropdownMenuProps struct {
Items []DropdownMenuItem // The list of items to display in the dropdown menu // Items defines the menu structure
Trigger templ.Component // An optional custom trigger component (default is a button if not provided) Items []DropdownMenuItem
Class string // Additional CSS classes to apply to the root element
Position string // The preferred position of the dropdown ("left", "right", "top", or "bottom") // Trigger overrides default button trigger
Trigger templ.Component
// Class adds custom CSS classes
Class string
// Position sets preferred menu placement (left, right, top, bottom)
Position string
} }
// ModifierClasses generates state-based CSS classes
func (d DropdownMenuItem) ModifierClasses() string { func (d DropdownMenuItem) ModifierClasses() string {
classes := []string{} classes := []string{}
if d.Disabled { if d.Disabled {
@ -40,8 +61,8 @@ func (d DropdownMenuItem) ModifierClasses() string {
return strings.Join(classes, " ") return strings.Join(classes, " ")
} }
// renderMenuItem is a helper function to render a single menu item // renderMenuItem handles recursive menu item rendering
// It handles rendering of regular items, links, and submenus recursively // Supports regular items, links, and nested submenus up to 3 levels
templ renderMenuItem(item DropdownMenuItem, index int, depth int) { templ renderMenuItem(item DropdownMenuItem, index int, depth int) {
if len(item.SubItems) > 0 { if len(item.SubItems) > 0 {
<div class="relative group"> <div class="relative group">
@ -134,41 +155,21 @@ templ renderMenuItem(item DropdownMenuItem, index int, depth int) {
} }
} }
// DropdownMenu renders an enhanced dropdown menu component // DropdownMenu renders a customizable popup menu with positioning and nesting support.
// It can be customized with various styles, positions, and behaviors. // Uses Alpine.js for interactions and supports keyboard navigation.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/dropdown-menu
// Usage:
//
// @components.DropdownMenu(components.DropdownMenuProps{
// Trigger: components.Button(components.ButtonProps{
// Text: "Open Menu",
// IconRight: components.Icon(components.IconProps{Name: "chevron-down"}),
// }),
// Position: "bottom",
// Items: []components.DropdownMenuItem{
// {Label: "Option 1", Value: "opt1"},
// {Label: "Option 2", Value: "opt2", IconLeft: components.Icon(components.IconProps{Name: "settings"})},
// {Label: "Submenu", SubItems: []components.DropdownMenuItem{
// {Label: "Sub Option 1", Value: "sub1"},
// {Label: "Sub Option 2", Value: "sub2"},
// }},
// },
// })
// //
// Props: // Props:
// - Items: Slice of DropdownMenuItem, defining the content of the dropdown // - Items: Menu structure and content
// - Trigger: Custom component to trigger the dropdown (optional, default is a basic button) // - Trigger: Custom trigger element (optional)
// - Class: Additional CSS classes to apply to the root element // - Class: Additional CSS classes
// - Position: Preferred position of the dropdown ("left", "right", "top", or "bottom") // - Position: Preferred placement
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil
// //
// Features: // Features:
// - Supports nested submenus up to 3 levels deep // - Nested submenus (up to 3 levels)
// - Automatically adjusts position based on available space // - Automatic position adjustment
// - Supports custom icons for menu items // - Keyboard navigation
// - Handles disabled states for menu items // - ARIA support
// - Uses Tailwind CSS for styling, including dark mode support
// - Implements keyboard navigation and ARIA attributes for accessibility
templ DropdownMenu(props DropdownMenuProps) { templ DropdownMenu(props DropdownMenuProps) {
<div <div
x-data="{ x-data="{

View File

@ -15,29 +15,50 @@ import (
"strings" "strings"
) )
// DropdownMenuItem represents an item in the dropdown menu
type DropdownMenuItem struct { type DropdownMenuItem struct {
Label string // The text to display for the menu item // Label displays text for the menu item
Value string // The value associated with the menu item (for non-link items) Label string
Href string // The URL to navigate to if the item is a link
Target string // The target attribute for link items (e.g., "_blank" for new tab) // Value for non-link menu items
IconLeft templ.Component // An optional icon component to display on the left side of the item Value string
IconRight templ.Component // An optional icon component to display on the right side of the item
SubItems []DropdownMenuItem // A slice of DropdownMenuItems for nested submenus // Href makes item a navigation link
Disabled bool // Whether the item is disabled or not Href string
// Attributes allows passing additional HTML attributes to the accordion container element.
// Default: nil // Target controls link opening behavior
Target string
// IconLeft displays icon before label
IconLeft templ.Component
// IconRight displays icon after label
IconRight templ.Component
// SubItems creates nested submenu
SubItems []DropdownMenuItem
// Disabled controls interactive state
Disabled bool
// Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// DropdownMenuProps defines the properties for the DropdownMenu component
type DropdownMenuProps struct { type DropdownMenuProps struct {
Items []DropdownMenuItem // The list of items to display in the dropdown menu // Items defines the menu structure
Trigger templ.Component // An optional custom trigger component (default is a button if not provided) Items []DropdownMenuItem
Class string // Additional CSS classes to apply to the root element
Position string // The preferred position of the dropdown ("left", "right", "top", or "bottom") // Trigger overrides default button trigger
Trigger templ.Component
// Class adds custom CSS classes
Class string
// Position sets preferred menu placement (left, right, top, bottom)
Position string
} }
// ModifierClasses generates state-based CSS classes
func (d DropdownMenuItem) ModifierClasses() string { func (d DropdownMenuItem) ModifierClasses() string {
classes := []string{} classes := []string{}
if d.Disabled { if d.Disabled {
@ -48,8 +69,8 @@ func (d DropdownMenuItem) ModifierClasses() string {
return strings.Join(classes, " ") return strings.Join(classes, " ")
} }
// renderMenuItem is a helper function to render a single menu item // renderMenuItem handles recursive menu item rendering
// It handles rendering of regular items, links, and submenus recursively // Supports regular items, links, and nested submenus up to 3 levels
func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component { func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -106,7 +127,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index)) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 57, Col: 43} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 78, Col: 43}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -139,7 +160,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 67, Col: 17} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 88, Col: 17}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -210,7 +231,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Target) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Target)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 88, Col: 23} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 109, Col: 23}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -236,7 +257,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var10 string var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index)) templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 96, Col: 42} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 117, Col: 42}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -263,7 +284,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var11 string var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label) templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 103, Col: 16} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 124, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -321,7 +342,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var14 string var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index)) templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 120, Col: 42} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 141, Col: 42}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -354,7 +375,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var15 string var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label) templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 128, Col: 16} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 149, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -379,41 +400,21 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
}) })
} }
// DropdownMenu renders an enhanced dropdown menu component // DropdownMenu renders a customizable popup menu with positioning and nesting support.
// It can be customized with various styles, positions, and behaviors. // Uses Alpine.js for interactions and supports keyboard navigation.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/dropdown-menu
// Usage:
//
// @components.DropdownMenu(components.DropdownMenuProps{
// Trigger: components.Button(components.ButtonProps{
// Text: "Open Menu",
// IconRight: components.Icon(components.IconProps{Name: "chevron-down"}),
// }),
// Position: "bottom",
// Items: []components.DropdownMenuItem{
// {Label: "Option 1", Value: "opt1"},
// {Label: "Option 2", Value: "opt2", IconLeft: components.Icon(components.IconProps{Name: "settings"})},
// {Label: "Submenu", SubItems: []components.DropdownMenuItem{
// {Label: "Sub Option 1", Value: "sub1"},
// {Label: "Sub Option 2", Value: "sub2"},
// }},
// },
// })
// //
// Props: // Props:
// - Items: Slice of DropdownMenuItem, defining the content of the dropdown // - Items: Menu structure and content
// - Trigger: Custom component to trigger the dropdown (optional, default is a basic button) // - Trigger: Custom trigger element (optional)
// - Class: Additional CSS classes to apply to the root element // - Class: Additional CSS classes
// - Position: Preferred position of the dropdown ("left", "right", "top", or "bottom") // - Position: Preferred placement
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil
// //
// Features: // Features:
// - Supports nested submenus up to 3 levels deep // - Nested submenus (up to 3 levels)
// - Automatically adjusts position based on available space // - Automatic position adjustment
// - Supports custom icons for menu items // - Keyboard navigation
// - Handles disabled states for menu items // - ARIA support
// - Uses Tailwind CSS for styling, including dark mode support
// - Implements keyboard navigation and ARIA attributes for accessibility
func DropdownMenu(props DropdownMenuProps) templ.Component { func DropdownMenu(props DropdownMenuProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -460,7 +461,7 @@ func DropdownMenu(props DropdownMenuProps) templ.Component {
var templ_7745c5c3_Var19 string var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(props.Position) templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(props.Position)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 199, Col: 32} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/dropdown_menu.templ`, Line: 200, Col: 32}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -2,116 +2,113 @@ package components
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// InputType represents the type of the input field. // InputType defines the available input field types
type InputType string type InputType string
// Constants for input types.
const ( const (
Text InputType = "text" // Standard text inputs
Password InputType = "password" InputTypeText InputType = "text"
Email InputType = "email" InputTypePassword InputType = "password"
Number InputType = "number" InputTypeEmail InputType = "email"
Tel InputType = "tel" InputTypeNumber InputType = "number"
URL InputType = "url" InputTypeTel InputType = "tel"
Search InputType = "search" InputTypeURL InputType = "url"
Date InputType = "date" InputTypeSearch InputType = "search"
Time InputType = "time"
File InputType = "file" // Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
) )
// InputProps defines the properties for the Input component.
type InputProps struct { type InputProps struct {
// Type specifies the type of the input field. // Type sets the input field behavior
// Default: Text
Type InputType Type InputType
// Placeholder is the placeholder text for the input field. // Placeholder shows helper text when empty
// Default: "" (empty string)
Placeholder string Placeholder string
// Value is the current value of the input field. // Value sets the current input content
// Default: "" (empty string)
Value string Value string
// Name is the name attribute of the input field. // Name sets the form field name
// Default: "" (empty string)
Name string Name string
// ID is the unique identifier for the input field. // ID uniquely identifies the input
// Default: "" (empty string)
ID string ID string
// Class specifies additional CSS classes to apply to the input field. // Label displays text above input
// Default: "" (empty string) Label string
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string Class string
// Disabled can be either a bool or a string. // FileAccept limits allowed file types
// If bool (Go), it directly controls the disabled state. // Only used when Type is InputTypeFile
// If string, it's treated as a JavaScript expression for dynamic disabling.
// Default: nil
Disabled any
// FileAccept specifies which file types are accepted (only for file type).
// Default: "" (empty string)
FileAccept string FileAccept string
// Attributes allows passing additional HTML attributes to the input element. // Attributes for additional HTML attributes and Alpine.js bindings
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Input renders an input component based on the provided props. // Input renders a form input field with optional label and validation.
// It can be customized with various types, sizes, and behaviors. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Usage:
//
// @components.Input(components.InputProps{
// Type: components.Email,
// Placeholder: "Enter your email",
// ID: "email-input",
// Class: "custom-input",
// Attributes: templ.Attributes{
// "aria-label": "Email input",
// "data-testid": "email-input",
// },
// })
// //
// Props: // Props:
// - Type: The type of the input field (e.g., Text, Email, Password). Default: Text // - Type: Input field behavior type
// - Placeholder: The placeholder text for the input field. Default: "" (empty string) // - Placeholder: Helper text when empty
// - Value: The current value of the input field. Default: "" (empty string) // - Value: Current input value
// - Name: The name attribute of the input field. Default: "" (empty string) // - Name: Form field name
// - ID: The unique identifier for the input field. Default: "" (empty string) // - ID: Unique identifier
// - Class: Additional CSS classes to apply to the input field. Default: "" (empty string) // - Label: Text label
// - Disabled: Can be either a bool or a string. If bool (Go), it directly controls the disabled state. If string, it's treated as a JavaScript expression for dynamic disabling. Default: nil // - Description: Helper text
// - FileAccept: Specifies which file types are accepted (only for file type). Default: "" (empty string) // - Error: Validation message
// - Attributes: Additional HTML attributes to apply to the input element. Default: nil // - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
templ Input(props InputProps) { templ Input(props InputProps) {
<input <span class="space-y-2">
type={ string(props.Type) } if props.Label != "" {
placeholder={ props.Placeholder } <label
value={ props.Value } for={ props.ID }
name={ props.Name } class={ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
id={ props.ID } templ.KV("text-destructive", len(props.Error)>0) }
class={ >
utils.TwMerge("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background", { props.Label }
"file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground", </label>
"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.Disabled != nil { <input
if disabledBool, ok := props.Disabled.(bool); ok && disabledBool { type={ string(props.Type) }
disabled="true" placeholder={ props.Placeholder }
name={ props.Name }
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 disabledStr, ok := props.Disabled.(string); ok { if props.Type == InputTypeFile {
:disabled={ disabledStr } accept={ props.FileAccept }
} }
{ props.Attributes... }
/>
if props.Description != "" {
<p class="text-sm text-muted-foreground m-0">{ props.Description }</p>
} }
if props.Type == File { if props.Error != "" {
accept={ props.FileAccept } <p class="text-sm font-medium text-destructive">{ props.Error }</p>
} }
{ props.Attributes... } </span>
/>
} }

View File

@ -10,90 +10,78 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// InputType represents the type of the input field. // InputType defines the available input field types
type InputType string type InputType string
// Constants for input types.
const ( const (
Text InputType = "text" // Standard text inputs
Password InputType = "password" InputTypeText InputType = "text"
Email InputType = "email" InputTypePassword InputType = "password"
Number InputType = "number" InputTypeEmail InputType = "email"
Tel InputType = "tel" InputTypeNumber InputType = "number"
URL InputType = "url" InputTypeTel InputType = "tel"
Search InputType = "search" InputTypeURL InputType = "url"
Date InputType = "date" InputTypeSearch InputType = "search"
Time InputType = "time"
File InputType = "file" // Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
) )
// InputProps defines the properties for the Input component.
type InputProps struct { type InputProps struct {
// Type specifies the type of the input field. // Type sets the input field behavior
// Default: Text
Type InputType Type InputType
// Placeholder is the placeholder text for the input field. // Placeholder shows helper text when empty
// Default: "" (empty string)
Placeholder string Placeholder string
// Value is the current value of the input field. // Value sets the current input content
// Default: "" (empty string)
Value string Value string
// Name is the name attribute of the input field. // Name sets the form field name
// Default: "" (empty string)
Name string Name string
// ID is the unique identifier for the input field. // ID uniquely identifies the input
// Default: "" (empty string)
ID string ID string
// Class specifies additional CSS classes to apply to the input field. // Label displays text above input
// Default: "" (empty string) Label string
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string Class string
// Disabled can be either a bool or a string. // FileAccept limits allowed file types
// If bool (Go), it directly controls the disabled state. // Only used when Type is InputTypeFile
// If string, it's treated as a JavaScript expression for dynamic disabling.
// Default: nil
Disabled any
// FileAccept specifies which file types are accepted (only for file type).
// Default: "" (empty string)
FileAccept string FileAccept string
// Attributes allows passing additional HTML attributes to the input element. // Attributes for additional HTML attributes and Alpine.js bindings
// Default: nil
Attributes templ.Attributes Attributes templ.Attributes
} }
// Input renders an input component based on the provided props. // Input renders a form input field with optional label and validation.
// It can be customized with various types, sizes, and behaviors. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Usage:
//
// @components.Input(components.InputProps{
// Type: components.Email,
// Placeholder: "Enter your email",
// ID: "email-input",
// Class: "custom-input",
// Attributes: templ.Attributes{
// "aria-label": "Email input",
// "data-testid": "email-input",
// },
// })
// //
// Props: // Props:
// - Type: The type of the input field (e.g., Text, Email, Password). Default: Text // - Type: Input field behavior type
// - Placeholder: The placeholder text for the input field. Default: "" (empty string) // - Placeholder: Helper text when empty
// - Value: The current value of the input field. Default: "" (empty string) // - Value: Current input value
// - Name: The name attribute of the input field. Default: "" (empty string) // - Name: Form field name
// - ID: The unique identifier for the input field. Default: "" (empty string) // - ID: Unique identifier
// - Class: Additional CSS classes to apply to the input field. Default: "" (empty string) // - Label: Text label
// - Disabled: Can be either a bool or a string. If bool (Go), it directly controls the disabled state. If string, it's treated as a JavaScript expression for dynamic disabling. Default: nil // - Description: Helper text
// - FileAccept: Specifies which file types are accepted (only for file type). Default: "" (empty string) // - Error: Validation message
// - Attributes: Additional HTML attributes to apply to the input element. Default: nil // - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
func Input(props InputProps) templ.Component { func Input(props InputProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -115,7 +103,62 @@ func Input(props InputProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent templ_7745c5c3_Var1 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{ _, 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: 81, 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: 85, 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", 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", "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", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
@ -123,7 +166,7 @@ func Input(props InputProps) templ.Component {
"file:text-foreground dark:file:text-foreground", "file:text-foreground dark:file:text-foreground",
props.Class), props.Class),
} }
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -131,12 +174,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var7 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type)) templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 91, Col: 27} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 89, Col: 28}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -144,25 +187,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 92, Col: 33} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 90, Col: 34}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, 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("\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 93, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -170,12 +200,25 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var9 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name) templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 94, Col: 19} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 91, 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_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/input.templ`, Line: 92, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -183,12 +226,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var7 string var templ_7745c5c3_Var11 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 95, Col: 15} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 93, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -196,12 +239,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var12 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String()) templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var6).String())
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 1, Col: 0} 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_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -209,44 +252,17 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
if props.Disabled != nil { if props.Type == InputTypeFile {
if disabledBool, ok := props.Disabled.(bool); ok && disabledBool {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" disabled=\"true\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if disabledStr, ok := props.Disabled.(string); ok {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" :disabled=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 109, Col: 27}
}
_, 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
}
}
}
if props.Type == File {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" accept=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" accept=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var10 string var templ_7745c5c3_Var13 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept) templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 113, Col: 28} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 103, Col: 29}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -259,7 +275,49 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">") _, 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: 108, 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: 111, 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>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -2,51 +2,21 @@ package components
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// ModalProps defines the properties for the Modal component.
type ModalProps struct { type ModalProps struct {
// ID is a unique identifier for the modal. // ID uniquely identifies the modal for open/close control
// It's used to control opening and closing.
// This should be unique across your application.
ID string ID string
// Class specifies additional CSS classes to apply to the modal container. // Class adds custom CSS classes
Class string Class string
} }
// Modal renders a modal dialog component. // Modal renders a popup dialog window with customizable content.
// It uses Alpine.js for state management and animations. // Uses Alpine.js for interactions and animations.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/modal
// //
// Usage: // Props:
// // - ID: Unique identifier for control
// @components.ModalTrigger("default-modal") { // - Class: Additional CSS classes
// @components.Button(components.ButtonProps{Text: "Open Modal"})
// }
//
// @components.Modal(components.ModalProps{ID: "default-modal", Class: "max-w-md"}) {
// @components.ModalHeader() {
// Are you absolutely sure?
// }
// @components.ModalBody() {
// This action cannot be undone. This will permanently delete your account and remove your data from our servers.
// }
// @components.ModalFooter() {
// <div class="flex gap-2">
// @components.ModalClose("default-modal") {
// @components.Button(components.ButtonProps{
// Text: "Cancel",
// })
// }
// @components.ModalClose("default-modal") {
// @components.Button(components.ButtonProps{
// Text: "Continue",
// Variant: components.Secondary,
// })
// }
// </div>
// }
// }
//
// The Modal component should be used in conjunction with ModalTrigger to open it.
templ Modal(props ModalProps) { templ Modal(props ModalProps) {
<div <div
x-data="{ open: false }" x-data="{ open: false }"
@ -79,15 +49,8 @@ templ Modal(props ModalProps) {
</div> </div>
} }
// ModalTrigger renders an element that opens the modal when clicked. // ModalTrigger creates clickable elements that open a modal
// // ID parameter must match the target modal's ID
// Usage:
//
// @components.ModalTrigger("example-modal") {
// @components.Button(components.ButtonProps{Text: "Open Modal"})
// }
//
// The 'id' parameter should match the ID of the Modal you want to open.
templ ModalTrigger(id string) { templ ModalTrigger(id string) {
<span <span
data-modal-id={ id } data-modal-id={ id }
@ -97,18 +60,8 @@ templ ModalTrigger(id string) {
</span> </span>
} }
// ModalClose renders an element that closes the modal when clicked. // ModalClose creates clickable elements that close a modal
// // ID parameter must match the target modal's ID
// Usage:
//
// @components.ModalClose("example-modal") {
// @components.Button(components.ButtonProps{
// Text: "Close",
// Variant: components.Secondary,
// })
// }
//
// The 'id' parameter should match the ID of the Modal you want to close.
templ ModalClose(id string) { templ ModalClose(id string) {
<span <span
data-modal-id={ id } data-modal-id={ id }
@ -118,14 +71,7 @@ templ ModalClose(id string) {
</span> </span>
} }
// ModalHeader renders the header section of the modal. // ModalHeader renders the modal title section
//
// Usage:
//
// @components.ModalHeader() {
// Modal Title
// @components.ModalClose("example-modal")
// }
templ ModalHeader() { templ ModalHeader() {
<div class="px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<h3 class="text-lg leading-6 font-medium text-foreground" id="modal-title"> <h3 class="text-lg leading-6 font-medium text-foreground" id="modal-title">
@ -134,31 +80,14 @@ templ ModalHeader() {
</div> </div>
} }
// ModalBody renders the main content area of the modal. /// ModalBody renders the main modal content area
//
// Usage:
//
// @components.ModalBody() {
// <p>This is the modal content.</p>
// }
templ ModalBody() { templ ModalBody() {
<div class="px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
{ children... } { children... }
</div> </div>
} }
// ModalFooter renders the footer section of the modal, typically containing action buttons. // ModalFooter renders the modal action buttons section
//
// Usage:
//
// @components.ModalFooter() {
// @components.ModalClose("example-modal") {
// @components.Button(components.ButtonProps{
// Text: "Close",
// Variant: components.Secondary,
// })
// }
// }
templ ModalFooter() { templ ModalFooter() {
<div class="px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> <div class="px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
{ children... } { children... }

View File

@ -10,51 +10,21 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils" import "github.com/axzilla/goilerplate/pkg/utils"
// ModalProps defines the properties for the Modal component.
type ModalProps struct { type ModalProps struct {
// ID is a unique identifier for the modal. // ID uniquely identifies the modal for open/close control
// It's used to control opening and closing.
// This should be unique across your application.
ID string ID string
// Class specifies additional CSS classes to apply to the modal container. // Class adds custom CSS classes
Class string Class string
} }
// Modal renders a modal dialog component. // Modal renders a popup dialog window with customizable content.
// It uses Alpine.js for state management and animations. // Uses Alpine.js for interactions and animations.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/modal
// //
// Usage: // Props:
// // - ID: Unique identifier for control
// @components.ModalTrigger("default-modal") { // - Class: Additional CSS classes
// @components.Button(components.ButtonProps{Text: "Open Modal"})
// }
//
// @components.Modal(components.ModalProps{ID: "default-modal", Class: "max-w-md"}) {
// @components.ModalHeader() {
// Are you absolutely sure?
// }
// @components.ModalBody() {
// This action cannot be undone. This will permanently delete your account and remove your data from our servers.
// }
// @components.ModalFooter() {
// <div class="flex gap-2">
// @components.ModalClose("default-modal") {
// @components.Button(components.ButtonProps{
// Text: "Cancel",
// })
// }
// @components.ModalClose("default-modal") {
// @components.Button(components.ButtonProps{
// Text: "Continue",
// Variant: components.Secondary,
// })
// }
// </div>
// }
// }
//
// The Modal component should be used in conjunction with ModalTrigger to open it.
func Modal(props ModalProps) templ.Component { func Modal(props ModalProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -83,7 +53,7 @@ func Modal(props ModalProps) templ.Component {
var templ_7745c5c3_Var2 string var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 55, Col: 26} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 25, Col: 26}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -131,15 +101,8 @@ func Modal(props ModalProps) templ.Component {
}) })
} }
// ModalTrigger renders an element that opens the modal when clicked. // ModalTrigger creates clickable elements that open a modal
// // ID parameter must match the target modal's ID
// Usage:
//
// @components.ModalTrigger("example-modal") {
// @components.Button(components.ButtonProps{Text: "Open Modal"})
// }
//
// The 'id' parameter should match the ID of the Modal you want to open.
func ModalTrigger(id string) templ.Component { func ModalTrigger(id string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -168,7 +131,7 @@ func ModalTrigger(id string) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(id) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(id)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 93, Col: 20} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 56, 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_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -190,18 +153,8 @@ func ModalTrigger(id string) templ.Component {
}) })
} }
// ModalClose renders an element that closes the modal when clicked. // ModalClose creates clickable elements that close a modal
// // ID parameter must match the target modal's ID
// Usage:
//
// @components.ModalClose("example-modal") {
// @components.Button(components.ButtonProps{
// Text: "Close",
// Variant: components.Secondary,
// })
// }
//
// The 'id' parameter should match the ID of the Modal you want to close.
func ModalClose(id string) templ.Component { func ModalClose(id string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -230,7 +183,7 @@ func ModalClose(id string) templ.Component {
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(id) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(id)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 114, Col: 20} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/modal.templ`, Line: 67, Col: 20}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -252,14 +205,7 @@ func ModalClose(id string) templ.Component {
}) })
} }
// ModalHeader renders the header section of the modal. // ModalHeader renders the modal title section
//
// Usage:
//
// @components.ModalHeader() {
// Modal Title
// @components.ModalClose("example-modal")
// }
func ModalHeader() templ.Component { func ModalHeader() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -297,13 +243,7 @@ func ModalHeader() templ.Component {
}) })
} }
// ModalBody renders the main content area of the modal. // / ModalBody renders the main modal content area
//
// Usage:
//
// @components.ModalBody() {
// <p>This is the modal content.</p>
// }
func ModalBody() templ.Component { func ModalBody() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -341,18 +281,7 @@ func ModalBody() templ.Component {
}) })
} }
// ModalFooter renders the footer section of the modal, typically containing action buttons. // ModalFooter renders the modal action buttons section
//
// Usage:
//
// @components.ModalFooter() {
// @components.ModalClose("example-modal") {
// @components.Button(components.ButtonProps{
// Text: "Close",
// Variant: components.Secondary,
// })
// }
// }
func ModalFooter() templ.Component { func ModalFooter() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context

View File

@ -1,77 +1,48 @@
package components package components
import ( import "github.com/axzilla/goilerplate/pkg/utils"
"fmt"
"github.com/axzilla/goilerplate/pkg/utils"
)
// RadioGroupProps defines the properties for the RadioGroup component.
type RadioGroupProps struct { type RadioGroupProps struct {
// DefaultValue is the initial selected value for the radio group. // Name groups related radio buttons
DefaultValue string
// Name is the name attribute for the radio group, used to group radio buttons.
Name string Name string
// Required indicates whether the radio group is a required field. // Class adds custom CSS classes
Required bool
// Class specifies additional CSS classes to apply to the radio group container.
Class string Class string
// Attributes allows passing additional HTML attributes to the radio group container. // Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// RadioGroupItemProps defines the properties for the RadioGroupItem component.
type RadioGroupItemProps struct { type RadioGroupItemProps struct {
// Value is the value attribute for the radio button. // Value sets the radio button value
Value string Value string
// Name is the name attribute for the radio button, should match the RadioGroup's name. // Name matches parent RadioGroup name
Name string Name string
// ID is the unique identifier for the radio button, used for labeling. // ID uniquely identifies the radio button
ID string ID string
// Disabled is a string representing an Alpine.js expression for the disabled state. // Label displays text next to radio button
// It can be a boolean value ("true" or "false") or a more complex condition. Label templ.Component
// Examples:
// - "true" for always disabled
// - "false" for never disabled
// - "someVariable" to bind to an Alpine.js data property
// - "someCondition === true" for a dynamic condition
Disabled string
// Class specifies additional CSS classes to apply to the radio button container. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the radio button. // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
// Label is a templ.Component that represents the label for the radio button.
// If not provided, the Value will be used as the label text.
Label templ.Component
} }
// RadioGroup renders a group of radio buttons. // RadioGroup renders a set of mutually exclusive radio button options.
// It uses Alpine.js for managing the selected state. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
// //
// Usage: // Props:
// // - Name: Groups related radio buttons
// @components.RadioGroup(components.RadioGroupProps{ // - Class: Additional CSS classes
// DefaultValue: "option1", // - Attributes: Additional HTML attributes
// Name: "myRadioGroup",
// Required: true,
// Class: "my-custom-class",
// }) {
// // RadioGroupItem components go here
// }
templ RadioGroup(props RadioGroupProps) { templ RadioGroup(props RadioGroupProps) {
<div <div
role="radiogroup" role="radiogroup"
aria-required={ fmt.Sprintf("%t", props.Required) }
x-data={ fmt.Sprintf(`{ selectedValue: '%s' }`, props.DefaultValue) }
class={ utils.TwMerge("space-y-2", props.Class) } class={ utils.TwMerge("space-y-2", props.Class) }
{ props.Attributes... } { props.Attributes... }
> >
@ -79,71 +50,47 @@ templ RadioGroup(props RadioGroupProps) {
</div> </div>
} }
// RadioGroupItem renders a single radio button with an integrated label. // RadioGroupItem renders an individual radio button with label.
// It uses Alpine.js for managing the disabled state and selected value. // Must be used within a RadioGroup component.
// //
// Usage: // Props:
// // - Value: Radio button value
// @components.RadioGroupItem(components.RadioGroupItemProps{ // - Name: Matches parent group name
// Value: "option1", // - ID: Unique identifier
// Name: "myRadioGroup", // - Label: Button label
// ID: "option1", // - Class: Additional CSS classes
// Disabled: "someCondition === true", // Alpine.js expression // - Attributes: Additional HTML attributes
// Label: templ.Raw("Option 1"),
// })
templ RadioGroupItem(props RadioGroupItemProps) { templ RadioGroupItem(props RadioGroupItemProps) {
<style> <label
/* Custom styles for radio buttons */ for={ props.ID }
input[type="radio"] { class={ utils.TwMerge(
position: relative; "flex items-center gap-2 cursor-pointer text-sm font-medium",
} "text-muted-foreground [&:has(input:checked)]:text-foreground",
input[type="radio"]:checked::before { "[&:has(input:disabled)]:cursor-not-allowed [&:has(input:disabled)]:opacity-50",
content: ''; props.Class,
position: absolute; ) }
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
border-radius: 50%;
background-color: hsl(var(--background));
}
input[type="radio"]:focus {
outline: none;
box-shadow: 0 0 0 2px hsl(var(--ring) / 50%);
}
</style>
<div
class={ utils.TwMerge("flex items-center space-x-2", props.Class) }
x-data={ fmt.Sprintf(`{ isDisabled: %s }`, props.Disabled) }
> >
<input <input
type="radio" type="radio"
id={ props.ID } id={ props.ID }
name={ props.Name } name={ props.Name }
value={ props.Value } value={ props.Value }
:disabled="isDisabled" class="before:content[''] relative h-4 w-4 appearance-none rounded-full
x-model="selectedValue" border border-2 border-primary
class={ checked:border-primary checked:bg-primary
"h-4 w-4 translate-y-px appearance-none rounded-full border bg-background checked:border-primary checked:bg-primary", before:absolute before:left-1/2 before:top-1/2
"disabled:opacity-50 disabled:cursor-not-allowed", before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2
} before:rounded-full before:bg-background
style=" checked:before:visible
border-color: hsl(var(--input)); focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
transition: all 0.2s ease-in-out; focus-visible:ring-offset-2 focus-visible:ring-offset-background
" disabled:cursor-not-allowed"
{ props.Attributes... } { props.Attributes... }
/> />
<label if props.Label != nil {
for={ props.ID } @props.Label
class={ "text-sm font-medium leading-none text-foreground" } } else {
:class="{ 'opacity-50 cursor-not-allowed': isDisabled }" <span>{ props.Value }</span>
> }
if props.Label != nil { </label>
@props.Label
} else {
{ props.Value }
}
</label>
</div>
} }

View File

@ -8,73 +8,46 @@ package components
import "github.com/a-h/templ" import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime" import templruntime "github.com/a-h/templ/runtime"
import ( import "github.com/axzilla/goilerplate/pkg/utils"
"fmt"
"github.com/axzilla/goilerplate/pkg/utils"
)
// RadioGroupProps defines the properties for the RadioGroup component.
type RadioGroupProps struct { type RadioGroupProps struct {
// DefaultValue is the initial selected value for the radio group. // Name groups related radio buttons
DefaultValue string
// Name is the name attribute for the radio group, used to group radio buttons.
Name string Name string
// Required indicates whether the radio group is a required field. // Class adds custom CSS classes
Required bool
// Class specifies additional CSS classes to apply to the radio group container.
Class string Class string
// Attributes allows passing additional HTML attributes to the radio group container. // Attributes for additional HTML attributes
Attributes templ.Attributes Attributes templ.Attributes
} }
// RadioGroupItemProps defines the properties for the RadioGroupItem component.
type RadioGroupItemProps struct { type RadioGroupItemProps struct {
// Value is the value attribute for the radio button. // Value sets the radio button value
Value string Value string
// Name is the name attribute for the radio button, should match the RadioGroup's name. // Name matches parent RadioGroup name
Name string Name string
// ID is the unique identifier for the radio button, used for labeling. // ID uniquely identifies the radio button
ID string ID string
// Disabled is a string representing an Alpine.js expression for the disabled state. // Label displays text next to radio button
// It can be a boolean value ("true" or "false") or a more complex condition. Label templ.Component
// Examples:
// - "true" for always disabled
// - "false" for never disabled
// - "someVariable" to bind to an Alpine.js data property
// - "someCondition === true" for a dynamic condition
Disabled string
// Class specifies additional CSS classes to apply to the radio button container. // Class adds custom CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes to the radio button. // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
// Label is a templ.Component that represents the label for the radio button.
// If not provided, the Value will be used as the label text.
Label templ.Component
} }
// RadioGroup renders a group of radio buttons. // RadioGroup renders a set of mutually exclusive radio button options.
// It uses Alpine.js for managing the selected state. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
// //
// Usage: // Props:
// // - Name: Groups related radio buttons
// @components.RadioGroup(components.RadioGroupProps{ // - Class: Additional CSS classes
// DefaultValue: "option1", // - Attributes: Additional HTML attributes
// Name: "myRadioGroup",
// Required: true,
// Class: "my-custom-class",
// }) {
// // RadioGroupItem components go here
// }
func RadioGroup(props RadioGroupProps) templ.Component { func RadioGroup(props RadioGroupProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -101,42 +74,16 @@ func RadioGroup(props RadioGroupProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div role=\"radiogroup\" aria-required=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div role=\"radiogroup\" class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%t", props.Required)) 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: 73, Col: 51}
}
_, 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("\" x-data=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`{ selectedValue: '%s' }`, props.DefaultValue))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 74, Col: 69}
}
_, 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 { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -164,18 +111,16 @@ func RadioGroup(props RadioGroupProps) templ.Component {
}) })
} }
// RadioGroupItem renders a single radio button with an integrated label. // RadioGroupItem renders an individual radio button with label.
// It uses Alpine.js for managing the disabled state and selected value. // Must be used within a RadioGroup component.
// //
// Usage: // Props:
// // - Value: Radio button value
// @components.RadioGroupItem(components.RadioGroupItemProps{ // - Name: Matches parent group name
// Value: "option1", // - ID: Unique identifier
// Name: "myRadioGroup", // - Label: Button label
// ID: "option1", // - Class: Additional CSS classes
// Disabled: "someCondition === true", // Alpine.js expression // - Attributes: Additional HTML attributes
// Label: templ.Raw("Option 1"),
// })
func RadioGroupItem(props RadioGroupItemProps) templ.Component { func RadioGroupItem(props RadioGroupItemProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -192,81 +137,70 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
}() }()
} }
ctx = templ.InitializeContext(ctx) ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx) templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil { if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var6 = templ.NopComponent templ_7745c5c3_Var4 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<style>\n\t\t/* Custom styles for radio buttons */\n\t\tinput[type=\"radio\"] {\n\t\t\tposition: relative;\n\t\t}\n\t\tinput[type=\"radio\"]:checked::before {\n\t\t\tcontent: '';\n\t\t\tposition: absolute;\n\t\t\ttop: 50%;\n\t\t\tleft: 50%;\n\t\t\ttransform: translate(-50%, -50%);\n\t\t\twidth: 8px;\n\t\t\theight: 8px;\n\t\t\tborder-radius: 50%;\n\t\t\tbackground-color: hsl(var(--background));\n\t\t}\n\t\tinput[type=\"radio\"]:focus {\n\t\t\toutline: none;\n\t\t\tbox-shadow: 0 0 0 2px hsl(var(--ring) / 50%);\n\t\t}\n\t</style>") 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var7 = []any{utils.TwMerge("flex items-center space-x-2", props.Class)} _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"") 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: 65, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var7).String()) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 75, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-data=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(`{ isDisabled: %s }`, props.Disabled))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 118, Col: 60}
}
_, 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
}
var templ_7745c5c3_Var10 = []any{
"h-4 w-4 translate-y-px appearance-none rounded-full border bg-background checked:border-primary checked:bg-primary",
"disabled:opacity-50 disabled:cursor-not-allowed",
}
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("<input type=\"radio\" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, 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: 122, Col: 16}
}
_, 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("\" name=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var12 string var templ_7745c5c3_Var9 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name) templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 123, Col: 20} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 76, Col: 20}
} }
_, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -274,29 +208,16 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var13 string var templ_7745c5c3_Var10 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value) templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 124, Col: 22} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 77, Col: 22}
} }
_, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :disabled=\"isDisabled\" x-model=\"selectedValue\" class=\"") _, 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
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, 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/radio_group.templ`, Line: 1, Col: 0}
}
_, 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("\" style=\"\n\t\t\t\tborder-color: hsl(var(--input));\n\t\t\t\ttransition: all 0.2s ease-in-out;\n\t\t\t\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -308,58 +229,31 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var15 = []any{"text-sm font-medium leading-none text-foreground"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var15...)
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_Var16 string
templ_7745c5c3_Var16, 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: 138, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var15).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_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :class=\"{ &#39;opacity-50 cursor-not-allowed&#39;: isDisabled }\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Label != nil { if props.Label != nil {
templ_7745c5c3_Err = props.Label.Render(ctx, templ_7745c5c3_Buffer) templ_7745c5c3_Err = props.Label.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} else { } else {
var templ_7745c5c3_Var18 string _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 145, Col: 17} return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 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: 93, 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 { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label></div>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -0,0 +1,81 @@
// pkg/components/select.templ
package components
import "github.com/axzilla/goilerplate/pkg/icons"
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
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
type SelectOption struct {
// Label displays text in dropdown
Label string
// Value sets the option's form value
Value string
// Attributes for disabled state or other HTML attributes
Attributes templ.Attributes
}
// Select renders a dropdown menu component with keyboard navigation.
// 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
templ Select(props SelectProps) {
<div class="relative">
<select
id={ props.ID }
name={ props.Name }
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"
{ props.Attributes... }
>
if props.Placeholder != "" {
<option value="" disabled selected hidden>{ props.Placeholder }</option>
}
for _, option := range props.Options {
<option
value={ option.Value }
{ option.Attributes... }
>
{ option.Label }
</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>
</div>
}

View File

@ -0,0 +1,196 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
// pkg/components/select.templ
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/icons"
type 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
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
type SelectOption struct {
// Label displays text in dropdown
Label string
// Value sets the option's form value
Value string
// Attributes for disabled state or other HTML attributes
Attributes templ.Attributes
}
// Select renders a dropdown menu component with keyboard navigation.
// 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
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
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"relative\"><select id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 57, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 58, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" 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\"")
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.Placeholder != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"\" disabled selected hidden>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, 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: 66, Col: 65}
}
_, 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("</option> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
for _, option := range props.Options {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, 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: 70, 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
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, option.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
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, 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: 73, Col: 19}
}
_, 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("</option>")
if templ_7745c5c3_Err != nil {
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\">")
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
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,38 +1,29 @@
package components package components
// SheetSide represents the side from which the sheet will appear. // SheetSide defines the slide-in direction
type SheetSide string type SheetSide string
// Constants for sheet sides.
const ( const (
Top SheetSide = "top" // Sheet appearance directions
Right SheetSide = "right" Top SheetSide = "top" // Slides down from top
Bottom SheetSide = "bottom" Right SheetSide = "right" // Slides in from right
Left SheetSide = "left" Bottom SheetSide = "bottom" // Slides up from bottom
Left SheetSide = "left" // Slides in from left
) )
// SheetProps defines the properties for the Sheet component.
type SheetProps struct { type SheetProps struct {
// Title is the heading text for the sheet. // Title displays in sheet header
// Default: "" (empty string)
Title string Title string
// Description is the subheading or description text for the sheet. // Description shows below title
// Default: "" (empty string)
Description string Description string
// Side determines from which side the sheet will appear. // Side controls slide-in direction
// Default: Right
Side SheetSide Side SheetSide
} }
// SheetRoot renders the root component for the Sheet, setting up the Alpine.js data and event handlers. // SheetRoot initializes Alpine.js state and event handlers
// // Must wrap Sheet components and triggers
// Usage:
//
// @components.SheetRoot() {
// // Sheet trigger and content go here
// }
templ SheetRoot() { templ SheetRoot() {
<div <div
x-data="{ x-data="{
@ -52,22 +43,20 @@ templ SheetRoot() {
</div> </div>
} }
// Sheet renders the main sheet component with backdrop and content. // Sheet renders a slide-in panel with backdrop.
// // Uses Alpine.js for animations and state management.
// Usage: // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/sheet
//
// @components.Sheet(components.SheetProps{
// Title: "Sheet Title",
// Description: "Sheet description goes here",
// Side: components.Right,
// }) {
// // Sheet content goes here
// }
// //
// Props: // Props:
// - Title: The heading text for the sheet. Default: "" (empty string) // - Title: Header text
// - Description: The subheading or description text for the sheet. Default: "" (empty string) // - Description: Subheading text
// - Side: Determines from which side the sheet will appear. Default: Right // - Side: Slide-in direction
//
// Features:
// - Responsive sizing
// - Animated transitions
// - Backdrop blur
// - ESC key closing
templ Sheet(props SheetProps) { templ Sheet(props SheetProps) {
<!-- Backdrop --> <!-- Backdrop -->
<div <div
@ -136,17 +125,8 @@ templ Sheet(props SheetProps) {
</div> </div>
} }
// SheetTrigger renders a trigger element that opens the sheet when clicked. // SheetTrigger creates elements that open the sheet
// // Must be used within SheetRoot
// Usage:
//
// @components.SheetTrigger("Open Sheet", components.Right) {
// <button>Open Sheet</button>
// }
//
// Props:
// - text: The text content of the trigger (unused in the current implementation)
// - side: The side from which the sheet should appear
templ SheetTrigger(text string, side SheetSide) { templ SheetTrigger(text string, side SheetSide) {
<span <span
@click={ "open('" + string(side) + "')" } @click={ "open('" + string(side) + "')" }
@ -155,14 +135,8 @@ templ SheetTrigger(text string, side SheetSide) {
</span> </span>
} }
// SheetClose renders a button that closes the sheet when clicked. // SheetClose creates a button that closes the sheet
// // Must be used within Sheet
// Usage:
//
// @components.SheetClose("Close")
//
// Props:
// - text: The text content of the close button
templ SheetClose(text string) { templ SheetClose(text string) {
<button <button
@click="close()" @click="close()"

View File

@ -8,39 +8,30 @@ package components
import "github.com/a-h/templ" import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime" import templruntime "github.com/a-h/templ/runtime"
// SheetSide represents the side from which the sheet will appear. // SheetSide defines the slide-in direction
type SheetSide string type SheetSide string
// Constants for sheet sides.
const ( const (
Top SheetSide = "top" // Sheet appearance directions
Right SheetSide = "right" Top SheetSide = "top" // Slides down from top
Bottom SheetSide = "bottom" Right SheetSide = "right" // Slides in from right
Left SheetSide = "left" Bottom SheetSide = "bottom" // Slides up from bottom
Left SheetSide = "left" // Slides in from left
) )
// SheetProps defines the properties for the Sheet component.
type SheetProps struct { type SheetProps struct {
// Title is the heading text for the sheet. // Title displays in sheet header
// Default: "" (empty string)
Title string Title string
// Description is the subheading or description text for the sheet. // Description shows below title
// Default: "" (empty string)
Description string Description string
// Side determines from which side the sheet will appear. // Side controls slide-in direction
// Default: Right
Side SheetSide Side SheetSide
} }
// SheetRoot renders the root component for the Sheet, setting up the Alpine.js data and event handlers. // SheetRoot initializes Alpine.js state and event handlers
// // Must wrap Sheet components and triggers
// Usage:
//
// @components.SheetRoot() {
// // Sheet trigger and content go here
// }
func SheetRoot() templ.Component { func SheetRoot() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -78,22 +69,20 @@ func SheetRoot() templ.Component {
}) })
} }
// Sheet renders the main sheet component with backdrop and content. // Sheet renders a slide-in panel with backdrop.
// // Uses Alpine.js for animations and state management.
// Usage: // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/sheet
//
// @components.Sheet(components.SheetProps{
// Title: "Sheet Title",
// Description: "Sheet description goes here",
// Side: components.Right,
// }) {
// // Sheet content goes here
// }
// //
// Props: // Props:
// - Title: The heading text for the sheet. Default: "" (empty string) // - Title: Header text
// - Description: The subheading or description text for the sheet. Default: "" (empty string) // - Description: Subheading text
// - Side: Determines from which side the sheet will appear. Default: Right // - Side: Slide-in direction
//
// Features:
// - Responsive sizing
// - Animated transitions
// - Backdrop blur
// - ESC key closing
func Sheet(props SheetProps) templ.Component { func Sheet(props SheetProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -176,7 +165,7 @@ func Sheet(props SheetProps) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Title) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Title)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 129, Col: 51} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 118, Col: 51}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -189,7 +178,7 @@ func Sheet(props SheetProps) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Description) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Description)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 130, Col: 64} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 119, Col: 64}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -211,17 +200,8 @@ func Sheet(props SheetProps) templ.Component {
}) })
} }
// SheetTrigger renders a trigger element that opens the sheet when clicked. // SheetTrigger creates elements that open the sheet
// // Must be used within SheetRoot
// Usage:
//
// @components.SheetTrigger("Open Sheet", components.Right) {
// <button>Open Sheet</button>
// }
//
// Props:
// - text: The text content of the trigger (unused in the current implementation)
// - side: The side from which the sheet should appear
func SheetTrigger(text string, side SheetSide) templ.Component { func SheetTrigger(text string, side SheetSide) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -250,7 +230,7 @@ func SheetTrigger(text string, side SheetSide) templ.Component {
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("open('" + string(side) + "')") templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("open('" + string(side) + "')")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 152, Col: 41} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 132, Col: 41}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -272,14 +252,8 @@ func SheetTrigger(text string, side SheetSide) templ.Component {
}) })
} }
// SheetClose renders a button that closes the sheet when clicked. // SheetClose creates a button that closes the sheet
// // Must be used within Sheet
// Usage:
//
// @components.SheetClose("Close")
//
// Props:
// - text: The text content of the close button
func SheetClose(text string) templ.Component { func SheetClose(text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -329,7 +303,7 @@ func SheetClose(text string) templ.Component {
var templ_7745c5c3_Var12 string var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(text) templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 174, Col: 8} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/sheet.templ`, Line: 148, Col: 8}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

109
pkg/components/slider.templ Normal file
View File

@ -0,0 +1,109 @@
package components
import (
"fmt"
"github.com/axzilla/goilerplate/pkg/utils"
)
type SliderProps struct {
// ID is the unique identifier for the slider
ID string
// Name is the name attribute for the slider
Name string
// Min sets the minimum value (default: 0)
Min int
// Max sets the maximum value (default: 100)
Max int
// Step defines the increment between values (default: 1)
Step int
// Value sets the initial value
Value int
// Label displays a label above the slider
Label string
// ShowValue toggles the value display
ShowValue bool
// ValueFormat adds a suffix to the value (e.g. "%", "°C")
ValueFormat string
// Class adds custom CSS classes
Class string
// Disabled makes the slider non-interactive
Disabled bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Slider renders a range input component with support for labels, value display and external binding.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/slider
//
// Props:
// - ID: Unique identifier for the slider
// - Name: Input name attribute
// - Min: Minimum value (default: 0)
// - Max: Maximum value (default: 100)
// - Step: Value increment (default: 1)
// - Value: Initial value
// - Label: Optional label text
// - ShowValue: Show current value
// - ValueFormat: Optional format suffix (e.g. "%", "°C")
// - Class: Additional CSS classes
// - Disabled: Disables the slider
// - Attributes: Additional HTML attributes (e.g. x-model for binding)
templ Slider(props SliderProps) {
<div
class="space-y-2"
x-data={ fmt.Sprintf("{ value: %d }", props.Value) }
>
if props.Label != "" || props.ShowValue {
<div class="flex justify-between items-center">
if props.Label != "" {
<label for={ props.ID } class="text-sm font-medium">
{ props.Label }
</label>
}
if props.ShowValue {
<p class="text-sm text-muted-foreground">
<span x-text="value"></span>
if props.ValueFormat != "" {
{ " " + props.ValueFormat }
}
</p>
}
</div>
}
<input
@input="value = $event.target.value"
type="range"
id={ props.ID }
name={ props.Name }
value={ fmt.Sprintf("%d", props.Value) }
min={ fmt.Sprintf("%d", props.Min) }
max={ fmt.Sprintf("%d", props.Max) }
step={ fmt.Sprintf("%d", props.Step) }
class={ utils.TwMerge(
"w-full h-2 rounded-full bg-secondary appearance-none cursor-pointer",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4",
"[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary",
"[&::-webkit-slider-thumb]:hover:bg-primary/90",
"[&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:border-0",
"[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary",
"[&::-moz-range-thumb]:hover:bg-primary/90",
"disabled:opacity-50 disabled:cursor-not-allowed",
props.Class,
) }
disabled?={ props.Disabled }
{ props.Attributes... }
/>
</div>
}

View File

@ -0,0 +1,300 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
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 (
"fmt"
"github.com/axzilla/goilerplate/pkg/utils"
)
type SliderProps struct {
// ID is the unique identifier for the slider
ID string
// Name is the name attribute for the slider
Name string
// Min sets the minimum value (default: 0)
Min int
// Max sets the maximum value (default: 100)
Max int
// Step defines the increment between values (default: 1)
Step int
// Value sets the initial value
Value int
// Label displays a label above the slider
Label string
// ShowValue toggles the value display
ShowValue bool
// ValueFormat adds a suffix to the value (e.g. "%", "°C")
ValueFormat string
// Class adds custom CSS classes
Class string
// Disabled makes the slider non-interactive
Disabled bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Slider renders a range input component with support for labels, value display and external binding.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/slider
//
// Props:
// - ID: Unique identifier for the slider
// - Name: Input name attribute
// - Min: Minimum value (default: 0)
// - Max: Maximum value (default: 100)
// - Step: Value increment (default: 1)
// - Value: Initial value
// - Label: Optional label text
// - ShowValue: Show current value
// - ValueFormat: Optional format suffix (e.g. "%", "°C")
// - Class: Additional CSS classes
// - Disabled: Disables the slider
// - Attributes: Additional HTML attributes (e.g. x-model for binding)
func Slider(props SliderProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"space-y-2\" x-data=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("{ value: %d }", props.Value))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 65, Col: 52}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Label != "" || props.ShowValue {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex justify-between items-center\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Label != "" {
_, 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/slider.templ`, Line: 70, Col: 26}
}
_, 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=\"text-sm font-medium\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 71, Col: 19}
}
_, 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("</label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if props.ShowValue {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-sm text-muted-foreground\"><span x-text=\"value\"></span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.ValueFormat != "" {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" " + props.ValueFormat)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 78, Col: 32}
}
_, 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("</p>")
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
}
}
var templ_7745c5c3_Var6 = []any{utils.TwMerge(
"w-full h-2 rounded-full bg-secondary appearance-none cursor-pointer",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4",
"[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary",
"[&::-webkit-slider-thumb]:hover:bg-primary/90",
"[&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:border-0",
"[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary",
"[&::-moz-range-thumb]:hover:bg-primary/90",
"disabled:opacity-50 disabled:cursor-not-allowed",
props.Class,
)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input @input=\"value = $event.target.value\" type=\"range\" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 87, Col: 16}
}
_, 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("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 88, Col: 20}
}
_, 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("\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", props.Value))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 89, Col: 41}
}
_, 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("\" min=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", props.Min))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 90, Col: 37}
}
_, 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("\" max=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", props.Max))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 91, Col: 37}
}
_, 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("\" step=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", props.Step))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.templ`, Line: 92, Col: 39}
}
_, 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=\"")
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_Var6).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/slider.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
}
if props.Disabled {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" disabled")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,49 +1,41 @@
package components package components
// Tab represents a single tab in the Tabs component.
type Tab struct { type Tab struct {
// ID is the unique identifier for the tab. // ID uniquely identifies the tab
ID string ID string
// Title is the text displayed on the tab button. // Title displays in tab button
Title string Title string
// Content is the templ.Component to be rendered when the tab is active. // Content renders when tab is active
Content templ.Component Content templ.Component
} }
// TabsProps defines the properties for the Tabs component.
type TabsProps struct { type TabsProps struct {
// Tabs is an array of Tab structs representing each tab in the component. // Tabs defines the tabs structure and content
Tabs []Tab Tabs []Tab
// TabsContainerClass specifies additional CSS classes for the tabs container. // TabsContainerClass adds classes to tabs header
// Default: "" (empty string)
TabsContainerClass string TabsContainerClass string
// ContentContainerClass specifies additional CSS classes for the content container. // ContentContainerClass adds classes to content area
// Default: "" (empty string)
ContentContainerClass string ContentContainerClass string
} }
// Tabs renders a tabbed interface component based on the provided props. // Tabs renders a tabbed interface with animated transitions.
// It uses Alpine.js for interactivity and state management. // Uses Alpine.js for state management and interactions.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/tabs
// Usage:
//
// @components.Tabs(components.TabsProps{
// Tabs: []components.Tab{
// {ID: "1", Title: "Tab 1", Content: Tab1Content()},
// {ID: "2", Title: "Tab 2", Content: Tab2Content()},
// },
// TabsContainerClass: "w-full max-w-md",
// ContentContainerClass: "mt-4",
// })
// //
// Props: // Props:
// - Tabs: An array of Tab structs, each representing a tab in the interface. // - Tabs: Tab definitions and content
// - TabsContainerClass: Additional CSS classes for the tabs container. Default: "" (empty string) // - TabsContainerClass: Additional classes for header
// - ContentContainerClass: Additional CSS classes for the content container. Default: "" (empty string) // - ContentContainerClass: Additional classes for content
//
// Features:
// - Animated tab switching
// - Keyboard navigation
// - Responsive layout
// - ARIA support
templ Tabs(props TabsProps) { templ Tabs(props TabsProps) {
<div <div
x-data="{ x-data="{

View File

@ -8,50 +8,42 @@ package components
import "github.com/a-h/templ" import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime" import templruntime "github.com/a-h/templ/runtime"
// Tab represents a single tab in the Tabs component.
type Tab struct { type Tab struct {
// ID is the unique identifier for the tab. // ID uniquely identifies the tab
ID string ID string
// Title is the text displayed on the tab button. // Title displays in tab button
Title string Title string
// Content is the templ.Component to be rendered when the tab is active. // Content renders when tab is active
Content templ.Component Content templ.Component
} }
// TabsProps defines the properties for the Tabs component.
type TabsProps struct { type TabsProps struct {
// Tabs is an array of Tab structs representing each tab in the component. // Tabs defines the tabs structure and content
Tabs []Tab Tabs []Tab
// TabsContainerClass specifies additional CSS classes for the tabs container. // TabsContainerClass adds classes to tabs header
// Default: "" (empty string)
TabsContainerClass string TabsContainerClass string
// ContentContainerClass specifies additional CSS classes for the content container. // ContentContainerClass adds classes to content area
// Default: "" (empty string)
ContentContainerClass string ContentContainerClass string
} }
// Tabs renders a tabbed interface component based on the provided props. // Tabs renders a tabbed interface with animated transitions.
// It uses Alpine.js for interactivity and state management. // Uses Alpine.js for state management and interactions.
// // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/tabs
// Usage:
//
// @components.Tabs(components.TabsProps{
// Tabs: []components.Tab{
// {ID: "1", Title: "Tab 1", Content: Tab1Content()},
// {ID: "2", Title: "Tab 2", Content: Tab2Content()},
// },
// TabsContainerClass: "w-full max-w-md",
// ContentContainerClass: "mt-4",
// })
// //
// Props: // Props:
// - Tabs: An array of Tab structs, each representing a tab in the interface. // - Tabs: Tab definitions and content
// - TabsContainerClass: Additional CSS classes for the tabs container. Default: "" (empty string) // - TabsContainerClass: Additional classes for header
// - ContentContainerClass: Additional CSS classes for the content container. Default: "" (empty string) // - ContentContainerClass: Additional classes for content
//
// Features:
// - Animated tab switching
// - Keyboard navigation
// - Responsive layout
// - ARIA support
func Tabs(props TabsProps) templ.Component { func Tabs(props TabsProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -109,7 +101,7 @@ func Tabs(props TabsProps) templ.Component {
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Title) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Title)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/tabs.templ`, Line: 84, Col: 16} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/tabs.templ`, Line: 76, Col: 16}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -0,0 +1,99 @@
package components
import (
"github.com/axzilla/goilerplate/pkg/utils"
"strconv"
)
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
// 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
}
// Textarea renders a multi-line text input with optional validation.
// Uses Alpine.js for autoresize functionality when enabled.
// 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
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
id={ props.ID }
name={ props.Name }
value={ props.Value }
placeholder={ props.Placeholder }
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... }
></textarea>
if props.Description != "" {
<p class="text-sm text-muted-foreground">{ props.Description }</p>
}
if props.Error != "" {
<p class="text-sm font-medium text-destructive">{ props.Error }</p>
}
</div>
}

View File

@ -0,0 +1,306 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
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"
"strconv"
)
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
// 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
}
// Textarea renders a multi-line text input with optional validation.
// Uses Alpine.js for autoresize functionality when enabled.
// 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
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
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"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/textarea.templ`, Line: 63, 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: 67, 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...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<textarea id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 71, Col: 16}
}
_, 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("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, 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: 72, Col: 20}
}
_, 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("\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
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: 73, Col: 22}
}
_, 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("\" 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/textarea.templ`, Line: 74, Col: 34}
}
_, 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.Rows != 0 {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" rows=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, 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: 76, Col: 35}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" 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_Var6).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_Var12))
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.AutoResize {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" x-data=\"{ resize() { $el.style.height = &#39;80px&#39;; $el.style.height = $el.scrollHeight + &#39;px&#39; } }\" x-init=\"resize()\" @input=\"resize()\"")
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("></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: 93, 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: 96, 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>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,134 +1,71 @@
package components package components
// ToggleSize represents the size of the toggle // / ToggleSize defines the available toggle dimensions
type ToggleSize string type ToggleSize string
// ToggleLabelPlacement represents where the label should be placed // ToggleLabelPlacement defines label position options
type ToggleLabelPlacement string type ToggleLabelPlacement string
// ToggleProps defines the properties for the Toggle component
type ToggleProps struct { type ToggleProps struct {
// ID is the unique identifier for the toggle input // ID uniquely identifies the toggle
ID string ID string
// Name is the name attribute for the toggle input // Name sets the form field name
Name string Name string
// Label is the text label for the toggle // LabelLeft displays text before toggle
LabelLeft string LabelLeft string
// Label is the text label for the toggle // LabelRight displays text after toggle
LabelRight string LabelRight string
// It's treated as an Alpine.js expression for dynamic checking. // Class adds custom CSS classes
// Example bool: Checked: "true"
// Example string: Checked: "darkMode"
Checked string
// It's treated as an Alpine.js expression for dynamic checking.
// Example bool: Disabled: "true"
// Example string: Disabled: "isLoading"
Disabled string
// Class specifies additional CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Toggle renders a toggle switch component based on the provided props. // Toggle renders a switch control for boolean values.
// It can be customized with different label placements, and supports // Uses Alpine.js for state management and animations.
// both static and dynamic states through Alpine.js integration. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/toggle
//
// Usage:
//
// // Basic toggle with label
// @components.Toggle(components.ToggleProps{
// ID: "dark-mode",
// Name: "darkMode",
// LabelLeft: "Dark Mode",
// })
//
// // Toggle with Alpine.js binding
// @components.Toggle(components.ToggleProps{
// ID: "notifications",
// Name: "notifications",
// LabelLeft: "Enable Notifications",
// Checked: "notificationsEnabled",
// Disabled: "isLoading",
// })
//
// // Toggle with custom size and label placement
// @components.Toggle(components.ToggleProps{
// ID: "alerts",
// Name: "alerts",
// LabelLeft: "Alerts",
// })
// //
// Props: // Props:
// - ID: The unique identifier for the toggle input. Required. // - ID: Unique identifier
// - Name: The name attribute for the toggle input. Required. // - Name: Form field name
// - LabelLeft: The text label for the toggle. Optional. // - LabelLeft: Text before toggle
// - LabelRight: The text label for the toggle. Optional. // - LabelRight: Text after toggle
// - Checked: Controls the checked state. Can be bool or string for Alpine.js binding. Optional. // - Class: Additional CSS classes
// - Disabled: Controls the disabled state. Can be bool or string for Alpine.js binding. Optional. // - Attributes: Additional HTML attributes
// - Class: Additional CSS classes. Optional. //
// - Attributes: Additional HTML attributes. Optional. // Features:
// - Animated switching
// - Keyboard navigation
// - Label placement options
// - ARIA support
templ Toggle(props ToggleProps) { templ Toggle(props ToggleProps) {
<div x-data="{ checked: false }" class="flex items-center gap-2"> <label for={ props.ID } class="inline-flex cursor-pointer items-center gap-2">
<input <input
id={ props.ID } id={ props.ID }
type="checkbox" type="checkbox"
name={ props.Name } name={ props.Name }
class="hidden" class="peer sr-only"
if props.Checked != "" { role="switch"
x-init={ "checked = " + props.Checked } { props.Attributes... }
}
if props.Disabled != "" {
:disabled={ props.Disabled }
}
x-model="checked"
/> />
if props.LabelLeft != "" { if props.LabelLeft != "" {
<label <span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
@click="$refs.switchButton.click(); $refs.switchButton.focus()"
:id="$id('switch')"
:class="{ 'text-foreground': checked, 'text-muted-foreground': !checked, 'opacity-50 cursor-not-allowed': disabled }"
class="text-sm select-none"
x-cloak
>
{ props.LabelLeft } { props.LabelLeft }
</label> </span>
} }
// FIX: Browser console bug: Alpine Expression Error: Unexpected token '}' -> on :disabled attribute -> But it works <div
<button 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"
x-ref="switchButton" aria-hidden="true"
type="button" ></div>
@click="checked = !checked"
class={
"relative inline-flex h-6 py-0.5 focus:outline-none rounded-full w-10",
"disabled:opacity-50 disabled:cursor-not-allowed",
}
:class="checked ? 'bg-primary' : 'bg-neutral-200'"
:disabled={ props.Disabled }
x-cloak
>
<span
:class="checked ? 'translate-x-[18px] bg-secondary' : 'translate-x-0.5 bg-muted-foreground'"
class="w-5 h-5 duration-200 ease-in-out rounded-full shadow-md"
></span>
</button>
if props.LabelRight != "" { if props.LabelRight != "" {
<label <span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
@click="$refs.switchButton.click(); $refs.switchButton.focus()"
:id="$id('switch')"
:class="{ 'text-foreground': checked, 'text-muted-foreground': !checked, 'opacity-50 cursor-not-allowed': disabled }"
class="text-sm select-none"
x-cloak
>
{ props.LabelRight } { props.LabelRight }
</label> </span>
} }
</div> </label>
} }

View File

@ -8,81 +8,49 @@ package components
import "github.com/a-h/templ" import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime" import templruntime "github.com/a-h/templ/runtime"
// ToggleSize represents the size of the toggle // / ToggleSize defines the available toggle dimensions
type ToggleSize string type ToggleSize string
// ToggleLabelPlacement represents where the label should be placed // ToggleLabelPlacement defines label position options
type ToggleLabelPlacement string type ToggleLabelPlacement string
// ToggleProps defines the properties for the Toggle component
type ToggleProps struct { type ToggleProps struct {
// ID is the unique identifier for the toggle input // ID uniquely identifies the toggle
ID string ID string
// Name is the name attribute for the toggle input // Name sets the form field name
Name string Name string
// Label is the text label for the toggle // LabelLeft displays text before toggle
LabelLeft string LabelLeft string
// Label is the text label for the toggle // LabelRight displays text after toggle
LabelRight string LabelRight string
// It's treated as an Alpine.js expression for dynamic checking. // Class adds custom CSS classes
// Example bool: Checked: "true"
// Example string: Checked: "darkMode"
Checked string
// It's treated as an Alpine.js expression for dynamic checking.
// Example bool: Disabled: "true"
// Example string: Disabled: "isLoading"
Disabled string
// Class specifies additional CSS classes
Class string Class string
// Attributes allows passing additional HTML attributes // Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes Attributes templ.Attributes
} }
// Toggle renders a toggle switch component based on the provided props. // Toggle renders a switch control for boolean values.
// It can be customized with different label placements, and supports // Uses Alpine.js for state management and animations.
// both static and dynamic states through Alpine.js integration. // For detailed examples and usage guides, visit https://goilerplate.com/docs/components/toggle
//
// Usage:
//
// // Basic toggle with label
// @components.Toggle(components.ToggleProps{
// ID: "dark-mode",
// Name: "darkMode",
// LabelLeft: "Dark Mode",
// })
//
// // Toggle with Alpine.js binding
// @components.Toggle(components.ToggleProps{
// ID: "notifications",
// Name: "notifications",
// LabelLeft: "Enable Notifications",
// Checked: "notificationsEnabled",
// Disabled: "isLoading",
// })
//
// // Toggle with custom size and label placement
// @components.Toggle(components.ToggleProps{
// ID: "alerts",
// Name: "alerts",
// LabelLeft: "Alerts",
// })
// //
// Props: // Props:
// - ID: The unique identifier for the toggle input. Required. // - ID: Unique identifier
// - Name: The name attribute for the toggle input. Required. // - Name: Form field name
// - LabelLeft: The text label for the toggle. Optional. // - LabelLeft: Text before toggle
// - LabelRight: The text label for the toggle. Optional. // - LabelRight: Text after toggle
// - Checked: Controls the checked state. Can be bool or string for Alpine.js binding. Optional. // - Class: Additional CSS classes
// - Disabled: Controls the disabled state. Can be bool or string for Alpine.js binding. Optional. // - Attributes: Additional HTML attributes
// - Class: Additional CSS classes. Optional. //
// - Attributes: Additional HTML attributes. Optional. // Features:
// - Animated switching
// - Keyboard navigation
// - Label placement options
// - ARIA support
func Toggle(props ToggleProps) templ.Component { func Toggle(props ToggleProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 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 templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -104,155 +72,100 @@ func Toggle(props ToggleProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent templ_7745c5c3_Var1 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{ checked: false }\" class=\"flex items-center gap-2\"><input id=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var2 string var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID) templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 81, Col: 16} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 47, Col: 22}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"inline-flex cursor-pointer items-center gap-2\"><input 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/toggle.templ`, Line: 49, Col: 16}
}
_, 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=\"checkbox\" name=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"checkbox\" name=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 83, Col: 20} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 51, Col: 20}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"hidden\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"peer sr-only\" role=\"switch\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
if props.Checked != "" { templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" x-init=\"") if templ_7745c5c3_Err != nil {
if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("checked = " + props.Checked)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 86, Col: 41}
}
_, 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
}
} }
if props.Disabled != "" { _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("> ")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" :disabled=\"") if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.LabelLeft != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Disabled) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.LabelLeft)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 89, Col: 30} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 58, Col: 21}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" x-model=\"checked\"> ") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<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-[&#39;&#39;] peer-checked:bg-primary peer-checked:after:bg-secondary peer-disabled:opacity-50 peer-disabled:cursor-not-allowed\" aria-hidden=\"true\"></div>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
if props.LabelLeft != "" { if props.LabelRight != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label @click=\"$refs.switchButton.click(); $refs.switchButton.focus()\" :id=\"$id(&#39;switch&#39;)\" :class=\"{ &#39;text-foreground&#39;: checked, &#39;text-muted-foreground&#39;: !checked, &#39;opacity-50 cursor-not-allowed&#39;: disabled }\" class=\"text-sm select-none\" x-cloak>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.LabelLeft) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.LabelRight)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 101, Col: 21} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 67, Col: 22}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
var templ_7745c5c3_Var7 = []any{ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
"relative inline-flex h-6 py-0.5 focus:outline-none rounded-full w-10",
"disabled:opacity-50 disabled:cursor-not-allowed",
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button x-ref=\"switchButton\" type=\"button\" @click=\"checked = !checked\" 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_Var7).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.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("\" :class=\"checked ? &#39;bg-primary&#39; : &#39;bg-neutral-200&#39;\" :disabled=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Disabled)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 114, Col: 29}
}
_, 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("\" x-cloak><span :class=\"checked ? &#39;translate-x-[18px] bg-secondary&#39; : &#39;translate-x-0.5 bg-muted-foreground&#39;\" class=\"w-5 h-5 duration-200 ease-in-out rounded-full shadow-md\"></span></button> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.LabelRight != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label @click=\"$refs.switchButton.click(); $refs.switchButton.focus()\" :id=\"$id(&#39;switch&#39;)\" :class=\"{ &#39;text-foreground&#39;: checked, &#39;text-muted-foreground&#39;: !checked, &#39;opacity-50 cursor-not-allowed&#39;: disabled }\" class=\"text-sm select-none\" x-cloak>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.LabelRight)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/toggle.templ`, Line: 130, 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("</label>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@ -449,46 +449,47 @@ video {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%; --muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%; --muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%; --popover: 0 0% 100%;
--accent-foreground: 240 5.9% 10%; --popover-foreground: 240 10% 3.9%;
--destructive: 0 72.22% 50.59%; --card: 0 0% 100%;
--destructive-foreground: 0 0% 98%; --card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%; --border: 240 5.9% 90%;
--input: 240 5.9% 90%; --input: 240 5.9% 90%;
--ring: 240 5.9% 10%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: 240 10% 3.9%; --background: 20 14.3% 4.1%;
--foreground: 0 0% 98%; --foreground: 0 0% 95%;
--card: 240 10% 3.9%; --muted: 0 0% 15%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%; --muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%; --popover: 0 0% 9%;
--accent-foreground: 0 0% 98%; --popover-foreground: 0 0% 95%;
--destructive: 0 62.8% 30.6%; --card: 24 9.8% 10%;
--destructive-foreground: 0 0% 98%; --card-foreground: 0 0% 95%;
--border: 240 3.7% 15.9%; --border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%; --input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%; --primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem;
} }
* { * {
@ -628,8 +629,28 @@ body {
} }
} }
.static { .sr-only {
position: static; 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;
}
.visible {
visibility: visible;
}
.invisible {
visibility: hidden;
} }
.fixed { .fixed {
@ -670,6 +691,10 @@ body {
left: 0px; left: 0px;
} }
.left-1\/2 {
left: 50%;
}
.left-full { .left-full {
left: 100%; left: 100%;
} }
@ -678,10 +703,22 @@ body {
right: 0px; right: 0px;
} }
.right-3 {
right: 0.75rem;
}
.top-0 { .top-0 {
top: 0px; top: 0px;
} }
.top-1\/2 {
top: 50%;
}
.top-3 {
top: 0.75rem;
}
.top-full { .top-full {
top: 100%; top: 100%;
} }
@ -698,6 +735,10 @@ body {
z-index: 50; z-index: 50;
} }
.m-0 {
margin: 0px;
}
.mx-auto { .mx-auto {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@ -775,6 +816,16 @@ body {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
.size-3 {
width: 0.75rem;
height: 0.75rem;
}
.size-4 {
width: 1rem;
height: 1rem;
}
.h-1\/2 { .h-1\/2 {
height: 50%; height: 50%;
} }
@ -795,6 +846,10 @@ body {
height: 4rem; height: 4rem;
} }
.h-2 {
height: 0.5rem;
}
.h-4 { .h-4 {
height: 1rem; height: 1rem;
} }
@ -827,6 +882,10 @@ body {
height: 100%; height: 100%;
} }
.min-h-\[80px\] {
min-height: 80px;
}
.w-1\/3 { .w-1\/3 {
width: 33.333333%; width: 33.333333%;
} }
@ -851,10 +910,6 @@ body {
width: 1rem; width: 1rem;
} }
.w-5 {
width: 1.25rem;
}
.w-56 { .w-56 {
width: 14rem; width: 14rem;
} }
@ -875,10 +930,6 @@ body {
width: 100%; width: 100%;
} }
.max-w-md {
max-width: 28rem;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@ -887,11 +938,21 @@ body {
flex-shrink: 1; flex-shrink: 1;
} }
.-translate-x-1\/2 {
--tw-translate-x: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-x-full { .-translate-x-full {
--tw-translate-x: -100%; --tw-translate-x: -100%;
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)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.-translate-y-1\/2 {
--tw-translate-y: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-translate-y-full { .-translate-y-full {
--tw-translate-y: -100%; --tw-translate-y: -100%;
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)); 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));
@ -902,16 +963,6 @@ body {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-x-0\.5 {
--tw-translate-x: 0.125rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-x-\[18px\] {
--tw-translate-x: 18px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-x-full { .translate-x-full {
--tw-translate-x: 100%; --tw-translate-x: 100%;
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)); 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));
@ -927,11 +978,6 @@ body {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-y-px {
--tw-translate-y: 1px;
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));
}
.scale-100 { .scale-100 {
--tw-scale-x: 1; --tw-scale-x: 1;
--tw-scale-y: 1; --tw-scale-y: 1;
@ -962,6 +1008,10 @@ body {
user-select: none; user-select: none;
} }
.resize {
resize: both;
}
.appearance-none { .appearance-none {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
@ -1106,11 +1156,6 @@ body {
border-top-width: 1px; border-top-width: 1px;
} }
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.border-border { .border-border {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: hsl(var(--border) / var(--tw-border-opacity)); border-color: hsl(var(--border) / var(--tw-border-opacity));
@ -1174,11 +1219,6 @@ body {
background-color: hsl(var(--muted) / var(--tw-bg-opacity)); background-color: hsl(var(--muted) / var(--tw-bg-opacity));
} }
.bg-muted-foreground {
--tw-bg-opacity: 1;
background-color: hsl(var(--muted-foreground) / var(--tw-bg-opacity));
}
.bg-muted\/50 { .bg-muted\/50 {
background-color: hsl(var(--muted) / 0.5); background-color: hsl(var(--muted) / 0.5);
} }
@ -1262,11 +1302,6 @@ body {
padding-right: 2rem; padding-right: 2rem;
} }
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 { .py-1 {
padding-top: 0.25rem; padding-top: 0.25rem;
padding-bottom: 0.25rem; padding-bottom: 0.25rem;
@ -1459,10 +1494,6 @@ body {
opacity: 1; opacity: 1;
} }
.opacity-50 {
opacity: 0.5;
}
.opacity-80 { .opacity-80 {
opacity: 0.8; opacity: 0.8;
} }
@ -1479,12 +1510,6 @@ body {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
} }
.shadow-md {
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-sm { .shadow-sm {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@ -1520,6 +1545,11 @@ body {
--tw-ring-offset-color: hsl(var(--background) / 1); --tw-ring-offset-color: hsl(var(--background) / 1);
} }
.blur {
--tw-blur: blur(8px);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.filter { .filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
} }
@ -1624,6 +1654,107 @@ body {
color: hsl(var(--muted-foreground) / var(--tw-text-opacity)); color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
} }
.before\:absolute::before {
content: var(--tw-content);
position: absolute;
}
.before\:inset-0::before {
content: var(--tw-content);
inset: 0px;
}
.before\:left-1\/2::before {
content: var(--tw-content);
left: 50%;
}
.before\:top-1\/2::before {
content: var(--tw-content);
top: 50%;
}
.before\:h-1\.5::before {
content: var(--tw-content);
height: 0.375rem;
}
.before\:w-1\.5::before {
content: var(--tw-content);
width: 0.375rem;
}
.before\:-translate-x-1\/2::before {
content: var(--tw-content);
--tw-translate-x: -50%;
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));
}
.before\:-translate-y-1\/2::before {
content: var(--tw-content);
--tw-translate-y: -50%;
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));
}
.before\:rounded-full::before {
content: var(--tw-content);
border-radius: 9999px;
}
.before\:bg-background::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--background) / var(--tw-bg-opacity));
}
.after\:absolute::after {
content: var(--tw-content);
position: absolute;
}
.after\:left-0\.5::after {
content: var(--tw-content);
left: 0.125rem;
}
.after\:top-0\.5::after {
content: var(--tw-content);
top: 0.125rem;
}
.after\:h-5::after {
content: var(--tw-content);
height: 1.25rem;
}
.after\:w-5::after {
content: var(--tw-content);
width: 1.25rem;
}
.after\:rounded-full::after {
content: var(--tw-content);
border-radius: 9999px;
}
.after\:bg-muted-foreground::after {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--muted-foreground) / var(--tw-bg-opacity));
}
.after\:transition-all::after {
content: var(--tw-content);
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.after\:content-\[\'\'\]::after {
--tw-content: '';
content: var(--tw-content);
}
.checked\:border-primary:checked { .checked\:border-primary:checked {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: hsl(var(--primary) / var(--tw-border-opacity)); border-color: hsl(var(--primary) / var(--tw-border-opacity));
@ -1634,6 +1765,17 @@ body {
background-color: hsl(var(--primary) / var(--tw-bg-opacity)); background-color: hsl(var(--primary) / var(--tw-bg-opacity));
} }
.checked\:before\:visible:checked::before {
content: var(--tw-content);
visibility: visible;
}
.checked\:before\:bg-primary:checked::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.hover\:bg-accent:hover { .hover\:bg-accent:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: hsl(var(--accent) / var(--tw-bg-opacity)); background-color: hsl(var(--accent) / var(--tw-bg-opacity));
@ -1698,6 +1840,22 @@ body {
outline-offset: 2px; 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 { .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-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); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -1713,6 +1871,19 @@ body {
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity)); --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
} }
.focus\:ring-ring:focus {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
}
.focus\:ring-offset-2:focus {
--tw-ring-offset-width: 2px;
}
.checked\:focus\:outline-primary:focus:checked {
outline-color: hsl(var(--primary) / 1);
}
.focus-visible\:outline-none:focus-visible { .focus-visible\:outline-none:focus-visible {
outline: 2px solid transparent; outline: 2px solid transparent;
outline-offset: 2px; outline-offset: 2px;
@ -1733,6 +1904,14 @@ body {
--tw-ring-offset-width: 2px; --tw-ring-offset-width: 2px;
} }
.focus-visible\:ring-offset-background:focus-visible {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
.active\:outline-offset-0:active {
outline-offset: 0px;
}
.disabled\:pointer-events-none:disabled { .disabled\:pointer-events-none:disabled {
pointer-events: none; pointer-events: none;
} }
@ -1763,24 +1942,30 @@ body {
opacity: 1; opacity: 1;
} }
.peer:checked ~ .peer-checked\:visible {
visibility: visible;
}
.peer:checked ~ .peer-checked\:bg-primary { .peer:checked ~ .peer-checked\:bg-primary {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity)); background-color: hsl(var(--primary) / var(--tw-bg-opacity));
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-2 { .peer:checked ~ .peer-checked\:text-foreground {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-text-opacity: 1;
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); color: hsl(var(--foreground) / var(--tw-text-opacity));
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-ring { .peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
--tw-ring-opacity: 1; content: var(--tw-content);
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity)); --tw-translate-x: 16px;
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));
} }
.peer:focus-visible ~ .peer-focus-visible\:ring-offset-2 { .peer:checked ~ .peer-checked\:after\:bg-secondary::after {
--tw-ring-offset-width: 2px; content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
} }
.peer:disabled ~ .peer-disabled\:cursor-not-allowed { .peer:disabled ~ .peer-disabled\:cursor-not-allowed {
@ -1791,6 +1976,10 @@ body {
opacity: 0.5; opacity: 0.5;
} }
.peer:disabled ~ .peer-disabled\:opacity-70 {
opacity: 0.7;
}
.dark\:text-gray-200:is(.dark *) { .dark\:text-gray-200:is(.dark *) {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity)); color: rgb(229 231 235 / var(--tw-text-opacity));
@ -1820,10 +2009,6 @@ body {
height: 50%; height: 50%;
} }
.sm\:max-w-\[70\%\] {
max-width: 70%;
}
.sm\:flex-row-reverse { .sm\:flex-row-reverse {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
@ -1871,6 +2056,70 @@ body {
} }
} }
.\[\&\:\:-moz-range-thumb\]\:h-4::-moz-range-thumb {
height: 1rem;
}
.\[\&\:\:-moz-range-thumb\]\:w-4::-moz-range-thumb {
width: 1rem;
}
.\[\&\:\:-moz-range-thumb\]\:rounded-full::-moz-range-thumb {
border-radius: 9999px;
}
.\[\&\:\:-moz-range-thumb\]\:border-0::-moz-range-thumb {
border-width: 0px;
}
.\[\&\:\:-moz-range-thumb\]\:bg-primary::-moz-range-thumb {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.\[\&\:\:-moz-range-thumb\]\:hover\:bg-primary\/90:hover::-moz-range-thumb {
background-color: hsl(var(--primary) / 0.9);
}
.\[\&\:\:-webkit-slider-thumb\]\:h-4::-webkit-slider-thumb {
height: 1rem;
}
.\[\&\:\:-webkit-slider-thumb\]\:w-4::-webkit-slider-thumb {
width: 1rem;
}
.\[\&\:\:-webkit-slider-thumb\]\:appearance-none::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
}
.\[\&\:\:-webkit-slider-thumb\]\:rounded-full::-webkit-slider-thumb {
border-radius: 9999px;
}
.\[\&\:\:-webkit-slider-thumb\]\:bg-primary::-webkit-slider-thumb {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.\[\&\:\:-webkit-slider-thumb\]\:hover\:bg-primary\/90:hover::-webkit-slider-thumb {
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) { .\[\&\:has\(svg\)\]\:pl-11:has(svg) {
padding-left: 2.75rem; padding-left: 2.75rem;
} }

9950
repopack-output.txt Normal file

File diff suppressed because it is too large Load Diff