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

Merge branch 'dev'

This commit is contained in:
axzilla 2024-11-22 15:31:17 +07:00
commit 0485471ba9
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 {
--background: 0 0% 100%;
--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-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 72.22% 50.59%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 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;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--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%;
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--border: 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 {

View File

@ -449,46 +449,47 @@ video {
:root {
--background: 0 0% 100%;
--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-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 72.22% 50.59%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 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;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--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%;
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--border: 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 {
position: static;
}
@ -674,6 +699,10 @@ body {
left: 0px;
}
.left-1\/2 {
left: 50%;
}
.left-full {
left: 100%;
}
@ -686,6 +715,10 @@ body {
right: 0.5rem;
}
.right-3 {
right: 0.75rem;
}
.right-4 {
right: 1rem;
}
@ -694,10 +727,18 @@ body {
top: 0px;
}
.top-1\/2 {
top: 50%;
}
.top-2 {
top: 0.5rem;
}
.top-3 {
top: 0.75rem;
}
.top-full {
top: 100%;
}
@ -819,6 +860,16 @@ body {
aspect-ratio: 1 / 1;
}
.size-3 {
width: 0.75rem;
height: 0.75rem;
}
.size-4 {
width: 1rem;
height: 1rem;
}
.h-1\/2 {
height: 50%;
}
@ -839,6 +890,10 @@ body {
height: 4rem;
}
.h-2 {
height: 0.5rem;
}
.h-24 {
height: 6rem;
}
@ -887,6 +942,10 @@ body {
max-height: 24rem;
}
.min-h-\[80px\] {
min-height: 80px;
}
.min-h-screen {
min-height: 100vh;
}
@ -955,6 +1014,10 @@ body {
max-width: 80rem;
}
.max-w-lg {
max-width: 32rem;
}
.max-w-md {
max-width: 28rem;
}
@ -987,11 +1050,20 @@ body {
flex-shrink: 0;
}
.grow {
flex-grow: 1;
}
.-translate-x-1 {
--tw-translate-x: -0.25rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.-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 {
--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));
@ -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));
}
.-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 {
--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));
@ -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));
}
.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 {
--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));
@ -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));
}
.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 {
--tw-scale-x: 1;
--tw-scale-y: 1;
@ -1077,6 +1139,10 @@ body {
user-select: none;
}
.resize {
resize: both;
}
.list-decimal {
list-style-type: decimal;
}
@ -1196,10 +1262,10 @@ body {
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;
margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
}
.divide-y > :not([hidden]) ~ :not([hidden]) {
@ -1281,11 +1347,6 @@ body {
border-top-width: 1px;
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.border-border {
--tw-border-opacity: 1;
border-color: hsl(var(--border) / var(--tw-border-opacity));
@ -1358,11 +1419,6 @@ body {
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 {
background-color: hsl(var(--muted) / 0.5);
}
@ -1475,11 +1531,6 @@ body {
padding-right: 2rem;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
@ -1735,10 +1786,6 @@ body {
opacity: 1;
}
.opacity-50 {
opacity: 0.5;
}
.opacity-80 {
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);
}
.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 {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@ -1796,6 +1837,11 @@ body {
--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: 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));
}
.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 {
--tw-border-opacity: 1;
border-color: hsl(var(--primary) / var(--tw-border-opacity));
@ -1910,6 +2057,17 @@ body {
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 {
--tw-bg-opacity: 1;
background-color: hsl(var(--accent) / var(--tw-bg-opacity));
@ -1993,6 +2151,22 @@ body {
outline-offset: 2px;
}
.focus\:outline:focus {
outline-style: solid;
}
.focus\:outline-2:focus {
outline-width: 2px;
}
.focus\:outline-offset-2:focus {
outline-offset: 2px;
}
.focus\:outline-ring:focus {
outline-color: hsl(var(--ring) / 1);
}
.focus\:ring-2:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -2008,6 +2182,19 @@ body {
--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 {
outline: 2px solid transparent;
outline-offset: 2px;
@ -2034,6 +2221,14 @@ body {
--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 {
pointer-events: none;
}
@ -2064,24 +2259,30 @@ body {
opacity: 1;
}
.peer:checked ~ .peer-checked\:visible {
visibility: visible;
}
.peer:checked ~ .peer-checked\:bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.peer:focus-visible ~ .peer-focus-visible\:ring-2 {
--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);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
.peer:checked ~ .peer-checked\:text-foreground {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.peer:focus-visible ~ .peer-focus-visible\:ring-ring {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
.peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
content: var(--tw-content);
--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 {
--tw-ring-offset-width: 2px;
.peer:checked ~ .peer-checked\:after\:bg-secondary::after {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
}
.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) {
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/modal", templ.Handler(pages.Modal()))
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/slider", templ.Handler(pages.Slider()))
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()))
fmt.Println("Server is running on http://localhost:8090")

View File

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

View File

@ -51,7 +51,6 @@ templ BaseLayout() {
class="h-full flex flex-col transition-colors duration-200"
:class="{ 'bg-white text-black': !isDark, 'text-white': isDark }"
>
<div class="page-loader">Loading...</div>
<div class="flex flex-col min-h-screen">
{ children... }
</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
import (
@ -70,7 +68,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{
ID: "username",
Name: "username",
Type: components.Text,
Type: components.InputTypeText,
Placeholder: "Enter your username",
})
</div>
@ -79,7 +77,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{
ID: "email",
Name: "email",
Type: components.Email,
Type: components.InputTypeEmail,
Placeholder: "Enter your email",
})
</div>
@ -88,7 +86,7 @@ templ ThemePreview() {
@components.Input(components.InputProps{
ID: "password",
Name: "password",
Type: components.Password,
Type: components.InputTypePassword,
Placeholder: "Enter your password",
})
</div>
@ -103,28 +101,26 @@ templ ThemePreview() {
</div>
<div class="space-y-2">
<label class="text-sm font-medium">Preferred Contact Method</label>
@components.RadioGroup(components.RadioGroupProps{DefaultValue: "email", Name: "contact-method"}) {
<div class="space-y-2">
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "email",
ID: "contact-email",
Name: "contact-method",
Label: templ.Raw("Email"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "phone",
ID: "contact-phone",
Name: "contact-method",
Label: templ.Raw("Phone"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "mail",
ID: "contact-mail",
Name: "contact-method",
Label: templ.Raw("Physical Mail"),
Disabled: "true",
})
</div>
@components.RadioGroup(components.RadioGroupProps{Name: "contact-method"}) {
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "email",
ID: "contact-email",
Name: "contact-method",
Label: templ.Raw("Email"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "phone",
ID: "contact-phone",
Name: "contact-method",
Label: templ.Raw("Phone"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "mail",
ID: "contact-mail",
Name: "contact-method",
Label: templ.Raw("Physical Mail"),
Attributes: templ.Attributes{"disabled": "true"},
})
}
</div>
<div class="space-y-4">
@ -141,7 +137,7 @@ templ ThemePreview() {
ID: "notifications",
Name: "notifications",
LabelRight: "Enable notifications",
Checked: "true",
Attributes: templ.Attributes{"checked": "true"},
})
</div>
<div class="space-y-2">
@ -149,7 +145,7 @@ templ ThemePreview() {
ID: "beta",
Name: "beta",
LabelRight: "Join beta program",
Disabled: "true",
Attributes: templ.Attributes{"disabled": "true"},
})
</div>
</div>

View File

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

View File

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

View File

@ -1,35 +1,30 @@
package showcase
import (
"github.com/axzilla/goilerplate/pkg/components"
)
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioGroupShowcase() {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
<div>
@components.RadioGroup(components.RadioGroupProps{DefaultValue: "comfortable", Name: "view-mode"}) {
<div class="space-y-2">
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "default",
ID: "r1",
Name: "view-mode",
Label: templ.Raw("Default"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "comfortable",
ID: "r2",
Name: "view-mode",
Disabled: "true",
Label: templ.Raw("Comfortable"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "compact",
ID: "r3",
Name: "view-mode",
Label: templ.Raw("Compact"),
})
</div>
}
</div>
@components.RadioGroup(components.RadioGroupProps{}) {
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "default",
ID: "r1",
Name: "view-mode",
Label: templ.Raw("Default"),
Attributes: templ.Attributes{"checked": true},
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "comfortable",
ID: "r2",
Name: "view-mode",
Label: templ.Raw("Disabled"),
Attributes: templ.Attributes{"disabled": true},
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "compact",
ID: "r3",
Name: "view-mode",
Label: templ.Raw("Compact"),
})
}
</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">
<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{
Type: components.Text,
Type: components.InputTypeText,
Placeholder: "Name",
ID: "name",
Value: "John Doe",
@ -47,7 +47,7 @@ templ AccountTab() {
<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>
@components.Input(components.InputProps{
Type: components.Text,
Type: components.InputTypeText,
Placeholder: "Username",
ID: "username",
Value: "@johndoe",
@ -78,7 +78,7 @@ templ PasswordTab() {
Current Password
</label>
@components.Input(components.InputProps{
Type: components.Password,
Type: components.InputTypePassword,
Placeholder: "Current Password",
ID: "current_password",
})
@ -88,7 +88,7 @@ templ PasswordTab() {
New Password
</label>
@components.Input(components.InputProps{
Type: components.Password,
Type: components.InputTypePassword,
Placeholder: "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>
<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{
ID: "toggle-checked",
Name: "toggle-checked",
LabelRight: "Checked Toggle",
Checked: "1+1==2",
Attributes: templ.Attributes{"x-bind:checked": "true"},
})
@components.Toggle(components.ToggleProps{
ID: "toggle-disabled",
Name: "toggle-disabled",
LabelRight: "Disabled Toggle",
Disabled: "true",
Attributes: templ.Attributes{"disabled": "true"},
})
@components.Toggle(components.ToggleProps{
ID: "toggle-disabled-checked",
Name: "toggle-disabled-checked",
LabelRight: "Disabled Checked Toggle",
Disabled: "true",
Checked: "true",
Attributes: templ.Attributes{"checked": "true", "disabled": true},
})
</div>
</div>

View File

@ -5,61 +5,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// AccordionItem represents a single item in the Accordion component.
type AccordionItem struct {
// ID is the unique identifier for the accordion item.
// It is used to manage the open/closed state of the item.
// ID is the unique identifier for managing accordion item state
ID string
// Trigger is the content of the accordion item's header/trigger.
// This is typically text, but can be any templ.Component.
// Trigger is the content shown in the header/trigger area
// Can be any templ.Component (typically text)
Trigger templ.Component
// Content is the expandable content of the accordion item.
// This can be any templ.Component.
// Content is the expandable content section
// Can be any templ.Component
Content templ.Component
}
// AccordionProps defines the properties for the Accordion component.
type AccordionProps struct {
// Items is a slice of AccordionItem structs representing each item in the accordion.
// Items contains the accordion sections
Items []AccordionItem
// Class specifies additional CSS classes to apply to the accordion container.
// Default: "" (empty string)
// Class adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes to the accordion container element.
// Default: nil
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Accordion renders an accordion component based on the provided props.
// It uses Alpine.js for interactivity and state management.
//
// 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"},
// })
// Accordion renders a collapsible content section component with expand/collapse functionality.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/accordion
//
// Props:
// - Items: A slice of AccordionItem structs, each representing an item in the accordion.
// - Class: Additional CSS classes to apply to the accordion container. Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil
// - Items: Array of accordion sections with ID, trigger and content
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes (e.g. data-testid)
templ Accordion(props AccordionProps) {
<div
x-data="{

View File

@ -13,61 +13,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// AccordionItem represents a single item in the Accordion component.
type AccordionItem struct {
// ID is the unique identifier for the accordion item.
// It is used to manage the open/closed state of the item.
// ID is the unique identifier for managing accordion item state
ID string
// Trigger is the content of the accordion item's header/trigger.
// This is typically text, but can be any templ.Component.
// Trigger is the content shown in the header/trigger area
// Can be any templ.Component (typically text)
Trigger templ.Component
// Content is the expandable content of the accordion item.
// This can be any templ.Component.
// Content is the expandable content section
// Can be any templ.Component
Content templ.Component
}
// AccordionProps defines the properties for the Accordion component.
type AccordionProps struct {
// Items is a slice of AccordionItem structs representing each item in the accordion.
// Items contains the accordion sections
Items []AccordionItem
// Class specifies additional CSS classes to apply to the accordion container.
// Default: "" (empty string)
// Class adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes to the accordion container element.
// Default: nil
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Accordion renders an accordion component based on the provided props.
// It uses Alpine.js for interactivity and state management.
//
// 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"},
// })
// Accordion renders a collapsible content section component with expand/collapse functionality.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/accordion
//
// Props:
// - Items: A slice of AccordionItem structs, each representing an item in the accordion.
// - Class: Additional CSS classes to apply to the accordion container. Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil
// - Items: Array of accordion sections with ID, trigger and content
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes (e.g. data-testid)
func Accordion(props AccordionProps) 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
@ -127,7 +103,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("toggleItem('" + item.ID + "')")
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))
if templ_7745c5c3_Err != nil {
@ -140,7 +116,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'")
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))
if templ_7745c5c3_Err != nil {
@ -165,7 +141,7 @@ func Accordion(props AccordionProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("activeItem === '" + item.ID + "'")
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))
if templ_7745c5c3_Err != nil {

View File

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

View File

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

View File

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

View File

@ -14,36 +14,39 @@ import (
"strings"
)
// AvatarSize represents the size of the avatar.
// AvatarSize defines the available avatar dimensions
type AvatarSize string
const (
AvatarSizeSmall AvatarSize = "small"
// AvatarSizeSmall renders a small avatar (32x32px)
AvatarSizeSmall AvatarSize = "small"
// AvatarSizeMedium renders a medium avatar (48x48px)
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 {
// ImageSrc is the URL of the avatar image.
// If empty, initials will be used.
// ImageSrc is the URL for the avatar image
// If empty, initials will be shown instead
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
// Size determines the size of the avatar.
// Default: AvatarSizeMedium
// Size controls the avatar dimensions (small, medium, large)
Size AvatarSize
// Class specifies additional CSS classes to apply to the avatar.
// Class adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes to the avatar element.
// Attributes for additional HTML 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 {
parts := strings.Fields(name)
initials := ""
@ -58,7 +61,7 @@ func AvatarInitials(name string) string {
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 {
switch size {
case AvatarSizeSmall:
@ -70,24 +73,15 @@ func AvatarSizeClasses(size AvatarSize) string {
}
}
// Avatar renders an avatar component based on the provided props.
// It displays an image if ImageSrc is provided, otherwise it shows initials.
//
// Usage:
//
// @components.Avatar(components.AvatarProps{
// ImageSrc: "https://example.com/avatar.jpg",
// Name: "John Doe",
// Size: components.AvatarSizeMedium,
// Class: "border-2 border-blue-500",
// })
// Avatar renders a circular image or initials for user representation.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/avatar
//
// Props:
// - ImageSrc: The URL of the avatar image. Default: "" (empty string)
// - Name: The name used to generate initials if ImageSrc is empty. Default: "" (empty string)
// - Size: The size of the avatar (AvatarSizeSmall, AvatarSizeMedium, AvatarSizeLarge). Default: AvatarSizeMedium
// - Class: Additional CSS classes to apply to the avatar. Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the avatar element. Default: nil
// - ImageSrc: URL for the avatar image
// - Name: Text to generate initials from when no image is provided
// - Size: Avatar dimensions (small, medium, large)
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func Avatar(props AvatarProps) 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
@ -153,7 +147,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ImageSrc)
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))
if templ_7745c5c3_Err != nil {
@ -166,7 +160,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s's avatar", props.Name))
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))
if templ_7745c5c3_Err != nil {
@ -184,7 +178,7 @@ func Avatar(props AvatarProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(AvatarInitials(props.Name))
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))
if templ_7745c5c3_Err != nil {

View File

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

View File

@ -13,80 +13,67 @@ import (
"strings"
)
// ButtonVariant represents the visual style of the button.
// ButtonVariant defines the available button styles
type ButtonVariant string
// ButtonSize represents the size of the button.
// ButtonSize defines the available button dimensions
type ButtonSize string
// Constants for button variants and sizes.
const (
Default ButtonVariant = "default"
Destructive ButtonVariant = "destructive"
Outline ButtonVariant = "outline"
Secondary ButtonVariant = "secondary"
Ghost ButtonVariant = "ghost"
Link ButtonVariant = "link"
// Button style variants
Default ButtonVariant = "default" // Primary action button
Destructive ButtonVariant = "destructive" // Dangerous/warning action
Outline ButtonVariant = "outline" // Bordered button
Secondary ButtonVariant = "secondary" // Less prominent action
Ghost ButtonVariant = "ghost" // Minimal styling
Link ButtonVariant = "link" // Appears as a text link
Md ButtonSize = "md"
Sm ButtonSize = "sm"
Lg ButtonSize = "lg"
ButtonIcon ButtonSize = "icon"
// Button sizes
Md ButtonSize = "md" // Standard size
Sm ButtonSize = "sm" // Compact size
Lg ButtonSize = "lg" // Large size
ButtonIcon ButtonSize = "icon" // Square icon button
)
// Button defines the properties for the Button component.
type ButtonProps struct {
// Class specifies additional CSS classes to apply to the button.
// Default: "" (empty string)
// Class adds custom CSS classes
Class string
// Text is the content of the button.
// Default: "" (empty string)
// Text contains the button label
Text string
// Variant determines the visual style of the button.
// Default: Default
// Variant controls the button styling
Variant ButtonVariant
// Size sets the size of the button.
// Default: Md
// Size controls button dimensions
Size ButtonSize
// FullWidth determines whether the button should take up the full width of its container.
// Default: false
// FullWidth makes button expand to container width
FullWidth bool
// Href, if provided, renders the button as an anchor tag with this URL.
// Default: "" (empty string)
// Href turns the button into a link
Href string
// Target specifies the target attribute for the anchor tag (only used when Href is provided).
// Default: "" (empty string)
// Target controls link opening behavior
Target string
// 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.
// Disabled controls interactive state (bool or JS expression)
Disabled any
// Type specifies the type of the button. Default: "button"
// Default: "" (empty string)
// Type sets the button type attribute
Type string
// Attributes allows passing additional HTML attributes to the button or anchor element.
// Default: nil
// Attributes for additional HTML attributes
Attributes templ.Attributes
// IconLeft specifies an icon component to be displayed on the left side of the button text.
// Default: nil
// IconLeft displays an icon before text
IconLeft templ.Component
// IconRight specifies an icon component to be displayed on the right side of the button text.
// Default: nil
// IconRight displays an icon after text
IconRight templ.Component
}
// Variant als Methode
// variantClasses maps variants to their CSS classes
func (b ButtonProps) variantClasses() string {
switch b.Variant {
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 {
switch b.Size {
case Sm:
@ -118,6 +105,7 @@ func (b ButtonProps) sizeClasses() string {
}
}
// modifierClasses generates additional utility classes
func (b ButtonProps) modifierClasses() string {
classes := []string{}
if b.FullWidth {
@ -126,37 +114,22 @@ func (b ButtonProps) modifierClasses() string {
return strings.Join(classes, " ")
}
// Button renders a button or anchor component based on the provided props.
// It can be customized with various visual styles, sizes, and behaviors.
//
// 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",
// },
// })
// Button renders an interactive button or link component with consistent styling.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/button
//
// Props:
// - Class: Additional CSS classes to apply to the button. Default: "" (empty string)
// - Text: The text content of the button. Default: "" (empty string)
// - Variant: The visual style of the button (e.g., Default, Destructive, Outline). Default: Default
// - Size: The size of the button (Md, Sm, Lg, Icon). Default: Md
// - FullWidth: Whether the button should take up the full width of its container. Default: false
// - Href: If provided, renders the button as an anchor tag with this URL. Default: "" (empty string)
// - Target: The target attribute for the anchor tag (only used when Href is provided). Default: "" (empty string)
// - 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
// - Type: The type of the button. Default: "button"
// - Attributes: Additional HTML attributes to apply to the button or anchor element. Default: nil
// - IconLeft: An icon component to be displayed on the left side of the button text. Default: nil
// - IconRight: An icon component to be displayed on the right side of the button text. Default: nil
// - Class: Additional CSS classes
// - Text: Button label text
// - Variant: Visual style (default, destructive, outline, etc)
// - Size: Button dimensions (sm, md, lg, icon)
// - FullWidth: Expand to fill container
// - Href: Optional URL for link buttons
// - Target: Link target attribute
// - Disabled: Interactivity state
// - Type: Button type attribute
// - Attributes: Additional HTML attributes
// - IconLeft: Icon component before text
// - IconRight: Icon component after text
func Button(props ButtonProps) 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
@ -209,7 +182,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Target)
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))
if templ_7745c5c3_Err != nil {
@ -247,7 +220,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr)
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))
if templ_7745c5c3_Err != nil {
@ -320,7 +293,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Type)
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))
if templ_7745c5c3_Err != nil {
@ -348,7 +321,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(disabledStr)
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))
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 {
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
@ -420,7 +393,7 @@ func renderButtonContent(props ButtonProps) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Text)
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))
if templ_7745c5c3_Err != nil {

View File

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

View File

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

View File

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

View File

@ -13,60 +13,37 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// CheckboxProps defines the properties for the Checkbox component.
type CheckboxProps struct {
// ID is the unique identifier for the checkbox input.
// ID uniquely identifies the checkbox input
ID string
// Name is the name attribute for the checkbox input.
// Name sets the form field name
Name string
// Value is the value attribute for the checkbox input.
// Value sets the checkbox value
Value string
// Label is the text label associated with the checkbox.
// If empty, no label will be rendered.
// Label displays text next to checkbox
// Empty string hides the label
Label string
// Checked is a JavaScript expression for the checked state
// 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 adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Checkbox renders a customizable checkbox component with an associated label.
//
// 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"},
// })
// Checkbox renders a styled checkbox input with optional label.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
//
// Props:
// - ID: The unique identifier for the checkbox input. Required.
// - Name: The name attribute for the checkbox input. Required.
// - Value: The value attribute for the checkbox input. Required.
// - Label: The text label associated with the checkbox. Optional.
// - Checked: Determines the checked state. Can be a bool or a string for dynamic binding. Optional.
// - Disabled: Determines the disabled state. Can be a bool or a string for dynamic binding. Optional.
// - Class: Additional CSS classes to apply to the checkbox container. Optional.
// - Attributes: Additional HTML attributes to apply to the checkbox input element. Optional.
// - ID: Unique identifier for the input
// - Name: Form field name
// - Value: Checkbox value
// - Label: Optional text label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func Checkbox(props CheckboxProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -88,47 +65,65 @@ func Checkbox(props CheckboxProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
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...)
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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))
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
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 {
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))
if templ_7745c5c3_Err != nil {
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=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
return templ_7745c5c3_Err
}
@ -136,58 +131,16 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-ref=\"checkbox\" x-model=\"checked\"")
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\"")
_, 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
}
@ -195,7 +148,7 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
@ -203,43 +156,30 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
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 {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 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 {
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 }\">")
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>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}

View File

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

View File

@ -13,49 +13,43 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// DatepickerProps defines the properties for the Datepicker component.
type DatepickerProps struct {
// ID is the unique identifier for the datepicker input.
// ID uniquely identifies the datepicker input
ID string
// Name is the name attribute for the datepicker input.
// Name sets the form field name
Name string
// Placeholder is the placeholder text for the datepicker input.
// Placeholder shows helper text when empty
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"
// Default: "M d, Y"
// Format controls date string presentation
// 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
// Class specifies additional CSS classes to apply to the datepicker container.
// Class adds custom CSS classes
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
}
// Datepicker renders an enhanced datepicker component with an input field and a calendar view.
// It uses Alpine.js for interactivity and provides various formatting options and improved navigation.
// This version supports dark mode using Tailwind CSS variables.
//
// Usage:
//
// @components.Datepicker(components.DatepickerProps{
// ID: "my-datepicker",
// Name: "selected-date",
// Placeholder: "Select a date",
// Format: "YYYY-MM-DD",
// Class: "w-full",
// })
// Datepicker renders a calendar input component with popup date selection.
// Uses Alpine.js for interactions and supports dark mode via Tailwind.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/datepicker
//
// Props:
// - ID: The unique identifier for the datepicker input. Default: "" (empty string)
// - Name: The name attribute for the datepicker input. Default: "" (empty string)
// - Placeholder: The placeholder text for the datepicker input. Default: "" (empty string)
// - Format: The date format to use. Default: "M d, Y"
// - Class: Additional CSS classes to apply to the datepicker container. Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the datepicker input element. Default: nil
// - ID: Unique identifier for the input
// - Name: Form field name
// - Placeholder: Helper text when empty
// - Format: Date display format
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func Datepicker(props DatepickerProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -89,7 +83,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Format)
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))
if templ_7745c5c3_Err != nil {
@ -115,7 +109,7 @@ func Datepicker(props DatepickerProps) templ.Component {
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/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))
if templ_7745c5c3_Err != nil {
@ -128,7 +122,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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))
if templ_7745c5c3_Err != nil {
@ -141,13 +135,13 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 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))
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}

View File

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

View File

@ -15,29 +15,50 @@ import (
"strings"
)
// DropdownMenuItem represents an item in the dropdown menu
type DropdownMenuItem struct {
Label string // The text to display for the menu item
Value string // The value associated with the menu item (for non-link items)
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)
IconLeft templ.Component // An optional icon component to display on the left side of the item
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
Disabled bool // Whether the item is disabled or not
// Attributes allows passing additional HTML attributes to the accordion container element.
// Default: nil
// Label displays text for the menu item
Label string
// Value for non-link menu items
Value string
// Href makes item a navigation link
Href string
// 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
}
// DropdownMenuProps defines the properties for the DropdownMenu component
type DropdownMenuProps struct {
Items []DropdownMenuItem // The list of items to display in the dropdown menu
Trigger templ.Component // An optional custom trigger component (default is a button if not provided)
Class string // Additional CSS classes to apply to the root element
Position string // The preferred position of the dropdown ("left", "right", "top", or "bottom")
// Items defines the menu structure
Items []DropdownMenuItem
// 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 {
classes := []string{}
if d.Disabled {
@ -48,8 +69,8 @@ func (d DropdownMenuItem) ModifierClasses() string {
return strings.Join(classes, " ")
}
// renderMenuItem is a helper function to render a single menu item
// It handles rendering of regular items, links, and submenus recursively
// renderMenuItem handles recursive menu item rendering
// Supports regular items, links, and nested submenus up to 3 levels
func renderMenuItem(item DropdownMenuItem, index int, depth int) 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
@ -106,7 +127,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
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))
if templ_7745c5c3_Err != nil {
@ -139,7 +160,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
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))
if templ_7745c5c3_Err != nil {
@ -210,7 +231,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Target)
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))
if templ_7745c5c3_Err != nil {
@ -236,7 +257,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
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))
if templ_7745c5c3_Err != nil {
@ -263,7 +284,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
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))
if templ_7745c5c3_Err != nil {
@ -321,7 +342,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("menu-item-%d", index))
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))
if templ_7745c5c3_Err != nil {
@ -354,7 +375,7 @@ func renderMenuItem(item DropdownMenuItem, index int, depth int) templ.Component
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(item.Label)
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))
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
// It can be customized with various styles, positions, and behaviors.
//
// 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"},
// }},
// },
// })
// DropdownMenu renders a customizable popup menu with positioning and nesting support.
// Uses Alpine.js for interactions and supports keyboard navigation.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/dropdown-menu
//
// Props:
// - Items: Slice of DropdownMenuItem, defining the content of the dropdown
// - Trigger: Custom component to trigger the dropdown (optional, default is a basic button)
// - Class: Additional CSS classes to apply to the root element
// - Position: Preferred position of the dropdown ("left", "right", "top", or "bottom")
// - Attributes: Additional HTML attributes to apply to the accordion container element. Default: nil
// - Items: Menu structure and content
// - Trigger: Custom trigger element (optional)
// - Class: Additional CSS classes
// - Position: Preferred placement
//
// Features:
// - Supports nested submenus up to 3 levels deep
// - Automatically adjusts position based on available space
// - Supports custom icons for menu items
// - Handles disabled states for menu items
// - Uses Tailwind CSS for styling, including dark mode support
// - Implements keyboard navigation and ARIA attributes for accessibility
// - Nested submenus (up to 3 levels)
// - Automatic position adjustment
// - Keyboard navigation
// - ARIA support
func DropdownMenu(props DropdownMenuProps) 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
@ -460,7 +461,7 @@ func DropdownMenu(props DropdownMenuProps) templ.Component {
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(props.Position)
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))
if templ_7745c5c3_Err != nil {

View File

@ -2,116 +2,113 @@ package components
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
// Constants for input types.
const (
Text InputType = "text"
Password InputType = "password"
Email InputType = "email"
Number InputType = "number"
Tel InputType = "tel"
URL InputType = "url"
Search InputType = "search"
Date InputType = "date"
Time InputType = "time"
File InputType = "file"
// Standard text inputs
InputTypeText InputType = "text"
InputTypePassword InputType = "password"
InputTypeEmail InputType = "email"
InputTypeNumber InputType = "number"
InputTypeTel InputType = "tel"
InputTypeURL InputType = "url"
InputTypeSearch InputType = "search"
// Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
)
// InputProps defines the properties for the Input component.
type InputProps struct {
// Type specifies the type of the input field.
// Default: Text
// Type sets the input field behavior
Type InputType
// Placeholder is the placeholder text for the input field.
// Default: "" (empty string)
// Placeholder shows helper text when empty
Placeholder string
// Value is the current value of the input field.
// Default: "" (empty string)
// Value sets the current input content
Value string
// Name is the name attribute of the input field.
// Default: "" (empty string)
// Name sets the form field name
Name string
// ID is the unique identifier for the input field.
// Default: "" (empty string)
// ID uniquely identifies the input
ID string
// Class specifies additional CSS classes to apply to the input field.
// Default: "" (empty string)
// Label displays text above input
Label string
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string
// 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 any
// FileAccept specifies which file types are accepted (only for file type).
// Default: "" (empty string)
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
FileAccept string
// Attributes allows passing additional HTML attributes to the input element.
// Default: nil
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Input renders an input component based on the provided props.
// It can be customized with various types, sizes, and behaviors.
//
// 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",
// },
// })
// Input renders a form input field with optional label and validation.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Props:
// - Type: The type of the input field (e.g., Text, Email, Password). Default: Text
// - Placeholder: The placeholder text for the input field. Default: "" (empty string)
// - Value: The current value of the input field. Default: "" (empty string)
// - Name: The name attribute of the input field. Default: "" (empty string)
// - ID: The unique identifier for the input field. Default: "" (empty string)
// - Class: Additional CSS classes to apply to the input field. Default: "" (empty string)
// - 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
// - FileAccept: Specifies which file types are accepted (only for file type). Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the input element. Default: nil
// - Type: Input field behavior type
// - Placeholder: Helper text when empty
// - Value: Current input value
// - Name: Form field name
// - ID: Unique identifier
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
templ Input(props InputProps) {
<input
type={ string(props.Type) }
placeholder={ props.Placeholder }
value={ props.Value }
name={ props.Name }
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),
<span class="space-y-2">
if props.Label != "" {
<label
for={ props.ID }
class={ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
templ.KV("text-destructive", len(props.Error)>0) }
>
{ props.Label }
</label>
}
if props.Disabled != nil {
if disabledBool, ok := props.Disabled.(bool); ok && disabledBool {
disabled="true"
<input
type={ string(props.Type) }
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 {
:disabled={ disabledStr }
if props.Type == InputTypeFile {
accept={ props.FileAccept }
}
{ props.Attributes... }
/>
if props.Description != "" {
<p class="text-sm text-muted-foreground m-0">{ props.Description }</p>
}
if props.Type == File {
accept={ props.FileAccept }
if props.Error != "" {
<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"
// InputType represents the type of the input field.
// InputType defines the available input field types
type InputType string
// Constants for input types.
const (
Text InputType = "text"
Password InputType = "password"
Email InputType = "email"
Number InputType = "number"
Tel InputType = "tel"
URL InputType = "url"
Search InputType = "search"
Date InputType = "date"
Time InputType = "time"
File InputType = "file"
// Standard text inputs
InputTypeText InputType = "text"
InputTypePassword InputType = "password"
InputTypeEmail InputType = "email"
InputTypeNumber InputType = "number"
InputTypeTel InputType = "tel"
InputTypeURL InputType = "url"
InputTypeSearch InputType = "search"
// Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
)
// InputProps defines the properties for the Input component.
type InputProps struct {
// Type specifies the type of the input field.
// Default: Text
// Type sets the input field behavior
Type InputType
// Placeholder is the placeholder text for the input field.
// Default: "" (empty string)
// Placeholder shows helper text when empty
Placeholder string
// Value is the current value of the input field.
// Default: "" (empty string)
// Value sets the current input content
Value string
// Name is the name attribute of the input field.
// Default: "" (empty string)
// Name sets the form field name
Name string
// ID is the unique identifier for the input field.
// Default: "" (empty string)
// ID uniquely identifies the input
ID string
// Class specifies additional CSS classes to apply to the input field.
// Default: "" (empty string)
// Label displays text above input
Label string
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string
// 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 any
// FileAccept specifies which file types are accepted (only for file type).
// Default: "" (empty string)
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
FileAccept string
// Attributes allows passing additional HTML attributes to the input element.
// Default: nil
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Input renders an input component based on the provided props.
// It can be customized with various types, sizes, and behaviors.
//
// 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",
// },
// })
// Input renders a form input field with optional label and validation.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Props:
// - Type: The type of the input field (e.g., Text, Email, Password). Default: Text
// - Placeholder: The placeholder text for the input field. Default: "" (empty string)
// - Value: The current value of the input field. Default: "" (empty string)
// - Name: The name attribute of the input field. Default: "" (empty string)
// - ID: The unique identifier for the input field. Default: "" (empty string)
// - Class: Additional CSS classes to apply to the input field. Default: "" (empty string)
// - 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
// - FileAccept: Specifies which file types are accepted (only for file type). Default: "" (empty string)
// - Attributes: Additional HTML attributes to apply to the input element. Default: nil
// - Type: Input field behavior type
// - Placeholder: Helper text when empty
// - Value: Current input value
// - Name: Form field name
// - ID: Unique identifier
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
func Input(props InputProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -115,7 +103,62 @@ func Input(props InputProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
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",
"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",
@ -123,7 +166,7 @@ func Input(props InputProps) templ.Component {
"file:text-foreground dark:file:text-foreground",
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 {
return templ_7745c5c3_Err
}
@ -131,12 +174,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type))
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 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 {
return templ_7745c5c3_Err
}
@ -144,25 +187,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 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))
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))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -170,12 +200,25 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
return templ_7745c5c3_Err
}
@ -183,12 +226,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
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/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 {
return templ_7745c5c3_Err
}
@ -196,12 +239,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
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/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 {
return templ_7745c5c3_Err
}
@ -209,44 +252,17 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Disabled != nil {
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 {
if props.Type == InputTypeFile {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" accept=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept)
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 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 {
return templ_7745c5c3_Err
}
@ -259,7 +275,49 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}

View File

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

View File

@ -10,51 +10,21 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils"
// ModalProps defines the properties for the Modal component.
type ModalProps struct {
// ID is a unique identifier for the modal.
// It's used to control opening and closing.
// This should be unique across your application.
// ID uniquely identifies the modal for open/close control
ID string
// Class specifies additional CSS classes to apply to the modal container.
// Class adds custom CSS classes
Class string
}
// Modal renders a modal dialog component.
// It uses Alpine.js for state management and animations.
// Modal renders a popup dialog window with customizable content.
// Uses Alpine.js for interactions and animations.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/modal
//
// Usage:
//
// @components.ModalTrigger("default-modal") {
// @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.
// Props:
// - ID: Unique identifier for control
// - Class: Additional CSS classes
func Modal(props ModalProps) 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
@ -83,7 +53,7 @@ func Modal(props ModalProps) templ.Component {
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/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))
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.
//
// 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.
// ModalTrigger creates clickable elements that open a modal
// ID parameter must match the target modal's ID
func ModalTrigger(id string) 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
@ -168,7 +131,7 @@ func ModalTrigger(id string) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(id)
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))
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.
//
// 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.
// ModalClose creates clickable elements that close a modal
// ID parameter must match the target modal's ID
func ModalClose(id string) 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
@ -230,7 +183,7 @@ func ModalClose(id string) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(id)
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))
if templ_7745c5c3_Err != nil {
@ -252,14 +205,7 @@ func ModalClose(id string) templ.Component {
})
}
// ModalHeader renders the header section of the modal.
//
// Usage:
//
// @components.ModalHeader() {
// Modal Title
// @components.ModalClose("example-modal")
// }
// ModalHeader renders the modal title section
func ModalHeader() 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
@ -297,13 +243,7 @@ func ModalHeader() templ.Component {
})
}
// ModalBody renders the main content area of the modal.
//
// Usage:
//
// @components.ModalBody() {
// <p>This is the modal content.</p>
// }
// / ModalBody renders the main modal content area
func ModalBody() 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
@ -341,18 +281,7 @@ func ModalBody() templ.Component {
})
}
// ModalFooter renders the footer section of the modal, typically containing action buttons.
//
// Usage:
//
// @components.ModalFooter() {
// @components.ModalClose("example-modal") {
// @components.Button(components.ButtonProps{
// Text: "Close",
// Variant: components.Secondary,
// })
// }
// }
// ModalFooter renders the modal action buttons section
func ModalFooter() 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

View File

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

View File

@ -8,73 +8,46 @@ package components
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"fmt"
"github.com/axzilla/goilerplate/pkg/utils"
)
import "github.com/axzilla/goilerplate/pkg/utils"
// RadioGroupProps defines the properties for the RadioGroup component.
type RadioGroupProps struct {
// DefaultValue is the initial selected value for the radio group.
DefaultValue string
// Name is the name attribute for the radio group, used to group radio buttons.
// Name groups related radio buttons
Name string
// Required indicates whether the radio group is a required field.
Required bool
// Class specifies additional CSS classes to apply to the radio group container.
// Class adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes to the radio group container.
// Attributes for additional HTML attributes
Attributes templ.Attributes
}
// RadioGroupItemProps defines the properties for the RadioGroupItem component.
type RadioGroupItemProps struct {
// Value is the value attribute for the radio button.
// Value sets the radio button value
Value string
// Name is the name attribute for the radio button, should match the RadioGroup's name.
// Name matches parent RadioGroup name
Name string
// ID is the unique identifier for the radio button, used for labeling.
// ID uniquely identifies the radio button
ID string
// Disabled is a string representing an Alpine.js expression for the disabled state.
// It can be a boolean value ("true" or "false") or a more complex condition.
// 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
// Label displays text next to radio button
Label templ.Component
// Class specifies additional CSS classes to apply to the radio button container.
// Class adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes to the radio button.
// Attributes for additional HTML attributes and Alpine.js bindings
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.
// It uses Alpine.js for managing the selected state.
// RadioGroup renders a set of mutually exclusive radio button options.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
//
// Usage:
//
// @components.RadioGroup(components.RadioGroupProps{
// DefaultValue: "option1",
// Name: "myRadioGroup",
// Required: true,
// Class: "my-custom-class",
// }) {
// // RadioGroupItem components go here
// }
// Props:
// - Name: Groups related radio buttons
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func RadioGroup(props RadioGroupProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -101,42 +74,16 @@ func RadioGroup(props RadioGroupProps) templ.Component {
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%t", props.Required))
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())
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -164,18 +111,16 @@ func RadioGroup(props RadioGroupProps) templ.Component {
})
}
// RadioGroupItem renders a single radio button with an integrated label.
// It uses Alpine.js for managing the disabled state and selected value.
// RadioGroupItem renders an individual radio button with label.
// Must be used within a RadioGroup component.
//
// Usage:
//
// @components.RadioGroupItem(components.RadioGroupItemProps{
// Value: "option1",
// Name: "myRadioGroup",
// ID: "option1",
// Disabled: "someCondition === true", // Alpine.js expression
// Label: templ.Raw("Option 1"),
// })
// Props:
// - Value: Radio button value
// - Name: Matches parent group name
// - ID: Unique identifier
// - Label: Button label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func RadioGroupItem(props RadioGroupItemProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -192,81 +137,70 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<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 {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 = []any{utils.TwMerge("flex items-center space-x-2", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<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 {
return templ_7745c5c3_Err
}
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 {
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))
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_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=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
return templ_7745c5c3_Err
}
@ -274,29 +208,16 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :disabled=\"isDisabled\" x-model=\"selectedValue\" class=\"")
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\"")
_, 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
}
@ -308,58 +229,31 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
if templ_7745c5c3_Err != nil {
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 {
templ_7745c5c3_Err = props.Label.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
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 {
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 {
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
// SheetSide represents the side from which the sheet will appear.
// SheetSide defines the slide-in direction
type SheetSide string
// Constants for sheet sides.
const (
Top SheetSide = "top"
Right SheetSide = "right"
Bottom SheetSide = "bottom"
Left SheetSide = "left"
// Sheet appearance directions
Top SheetSide = "top" // Slides down from top
Right SheetSide = "right" // Slides in from right
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 {
// Title is the heading text for the sheet.
// Default: "" (empty string)
// Title displays in sheet header
Title string
// Description is the subheading or description text for the sheet.
// Default: "" (empty string)
// Description shows below title
Description string
// Side determines from which side the sheet will appear.
// Default: Right
// Side controls slide-in direction
Side SheetSide
}
// SheetRoot renders the root component for the Sheet, setting up the Alpine.js data and event handlers.
//
// Usage:
//
// @components.SheetRoot() {
// // Sheet trigger and content go here
// }
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="{
@ -52,22 +43,20 @@ templ SheetRoot() {
</div>
}
// Sheet renders the main sheet component with backdrop and content.
//
// Usage:
//
// @components.Sheet(components.SheetProps{
// Title: "Sheet Title",
// Description: "Sheet description goes here",
// Side: components.Right,
// }) {
// // Sheet content goes here
// }
// Sheet renders a slide-in panel with backdrop.
// Uses Alpine.js for animations and state management.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/sheet
//
// Props:
// - Title: The heading text for the sheet. Default: "" (empty string)
// - Description: The subheading or description text for the sheet. Default: "" (empty string)
// - Side: Determines from which side the sheet will appear. Default: Right
// - Title: Header text
// - Description: Subheading text
// - Side: Slide-in direction
//
// Features:
// - Responsive sizing
// - Animated transitions
// - Backdrop blur
// - ESC key closing
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
@ -136,17 +125,8 @@ templ Sheet(props SheetProps) {
</div>
}
// SheetTrigger renders a trigger element that opens the sheet when clicked.
//
// 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
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span
@click={ "open('" + string(side) + "')" }
@ -155,14 +135,8 @@ templ SheetTrigger(text string, side SheetSide) {
</span>
}
// SheetClose renders a button that closes the sheet when clicked.
//
// Usage:
//
// @components.SheetClose("Close")
//
// Props:
// - text: The text content of the close button
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close()"

View File

@ -8,39 +8,30 @@ package components
import "github.com/a-h/templ"
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
// Constants for sheet sides.
const (
Top SheetSide = "top"
Right SheetSide = "right"
Bottom SheetSide = "bottom"
Left SheetSide = "left"
// Sheet appearance directions
Top SheetSide = "top" // Slides down from top
Right SheetSide = "right" // Slides in from right
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 {
// Title is the heading text for the sheet.
// Default: "" (empty string)
// Title displays in sheet header
Title string
// Description is the subheading or description text for the sheet.
// Default: "" (empty string)
// Description shows below title
Description string
// Side determines from which side the sheet will appear.
// Default: Right
// Side controls slide-in direction
Side SheetSide
}
// SheetRoot renders the root component for the Sheet, setting up the Alpine.js data and event handlers.
//
// Usage:
//
// @components.SheetRoot() {
// // Sheet trigger and content go here
// }
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
func SheetRoot() 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
@ -78,22 +69,20 @@ func SheetRoot() templ.Component {
})
}
// Sheet renders the main sheet component with backdrop and content.
//
// Usage:
//
// @components.Sheet(components.SheetProps{
// Title: "Sheet Title",
// Description: "Sheet description goes here",
// Side: components.Right,
// }) {
// // Sheet content goes here
// }
// Sheet renders a slide-in panel with backdrop.
// Uses Alpine.js for animations and state management.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/sheet
//
// Props:
// - Title: The heading text for the sheet. Default: "" (empty string)
// - Description: The subheading or description text for the sheet. Default: "" (empty string)
// - Side: Determines from which side the sheet will appear. Default: Right
// - Title: Header text
// - Description: Subheading text
// - Side: Slide-in direction
//
// Features:
// - Responsive sizing
// - Animated transitions
// - Backdrop blur
// - ESC key closing
func Sheet(props SheetProps) 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
@ -176,7 +165,7 @@ func Sheet(props SheetProps) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Title)
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))
if templ_7745c5c3_Err != nil {
@ -189,7 +178,7 @@ func Sheet(props SheetProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Description)
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))
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.
//
// 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
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
func SheetTrigger(text string, side SheetSide) 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
@ -250,7 +230,7 @@ func SheetTrigger(text string, side SheetSide) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("open('" + string(side) + "')")
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))
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.
//
// Usage:
//
// @components.SheetClose("Close")
//
// Props:
// - text: The text content of the close button
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
func SheetClose(text string) 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
@ -329,7 +303,7 @@ func SheetClose(text string) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(text)
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))
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
// Tab represents a single tab in the Tabs component.
type Tab struct {
// ID is the unique identifier for the tab.
// ID uniquely identifies the tab
ID string
// Title is the text displayed on the tab button.
// Title displays in tab button
Title string
// Content is the templ.Component to be rendered when the tab is active.
// Content renders when tab is active
Content templ.Component
}
// TabsProps defines the properties for the Tabs component.
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
// TabsContainerClass specifies additional CSS classes for the tabs container.
// Default: "" (empty string)
// TabsContainerClass adds classes to tabs header
TabsContainerClass string
// ContentContainerClass specifies additional CSS classes for the content container.
// Default: "" (empty string)
// ContentContainerClass adds classes to content area
ContentContainerClass string
}
// Tabs renders a tabbed interface component based on the provided props.
// It uses Alpine.js for interactivity and state management.
//
// 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",
// })
// Tabs renders a tabbed interface with animated transitions.
// Uses Alpine.js for state management and interactions.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/tabs
//
// Props:
// - Tabs: An array of Tab structs, each representing a tab in the interface.
// - TabsContainerClass: Additional CSS classes for the tabs container. Default: "" (empty string)
// - ContentContainerClass: Additional CSS classes for the content container. Default: "" (empty string)
// - Tabs: Tab definitions and content
// - TabsContainerClass: Additional classes for header
// - ContentContainerClass: Additional classes for content
//
// Features:
// - Animated tab switching
// - Keyboard navigation
// - Responsive layout
// - ARIA support
templ Tabs(props TabsProps) {
<div
x-data="{

View File

@ -8,50 +8,42 @@ package components
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
// Tab represents a single tab in the Tabs component.
type Tab struct {
// ID is the unique identifier for the tab.
// ID uniquely identifies the tab
ID string
// Title is the text displayed on the tab button.
// Title displays in tab button
Title string
// Content is the templ.Component to be rendered when the tab is active.
// Content renders when tab is active
Content templ.Component
}
// TabsProps defines the properties for the Tabs component.
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
// TabsContainerClass specifies additional CSS classes for the tabs container.
// Default: "" (empty string)
// TabsContainerClass adds classes to tabs header
TabsContainerClass string
// ContentContainerClass specifies additional CSS classes for the content container.
// Default: "" (empty string)
// ContentContainerClass adds classes to content area
ContentContainerClass string
}
// Tabs renders a tabbed interface component based on the provided props.
// It uses Alpine.js for interactivity and state management.
//
// 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",
// })
// Tabs renders a tabbed interface with animated transitions.
// Uses Alpine.js for state management and interactions.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/tabs
//
// Props:
// - Tabs: An array of Tab structs, each representing a tab in the interface.
// - TabsContainerClass: Additional CSS classes for the tabs container. Default: "" (empty string)
// - ContentContainerClass: Additional CSS classes for the content container. Default: "" (empty string)
// - Tabs: Tab definitions and content
// - TabsContainerClass: Additional classes for header
// - ContentContainerClass: Additional classes for content
//
// Features:
// - Animated tab switching
// - Keyboard navigation
// - Responsive layout
// - ARIA support
func Tabs(props TabsProps) 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
@ -109,7 +101,7 @@ func Tabs(props TabsProps) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Title)
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))
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
// ToggleSize represents the size of the toggle
// / ToggleSize defines the available toggle dimensions
type ToggleSize string
// ToggleLabelPlacement represents where the label should be placed
// ToggleLabelPlacement defines label position options
type ToggleLabelPlacement string
// ToggleProps defines the properties for the Toggle component
type ToggleProps struct {
// ID is the unique identifier for the toggle input
// ID uniquely identifies the toggle
ID string
// Name is the name attribute for the toggle input
// Name sets the form field name
Name string
// Label is the text label for the toggle
// LabelLeft displays text before toggle
LabelLeft string
// Label is the text label for the toggle
// LabelRight displays text after toggle
LabelRight string
// It's treated as an Alpine.js expression for dynamic checking.
// 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 adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Toggle renders a toggle switch component based on the provided props.
// It can be customized with different label placements, and supports
// both static and dynamic states through Alpine.js integration.
//
// 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",
// })
// Toggle renders a switch control for boolean values.
// Uses Alpine.js for state management and animations.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/toggle
//
// Props:
// - ID: The unique identifier for the toggle input. Required.
// - Name: The name attribute for the toggle input. Required.
// - LabelLeft: The text label for the toggle. Optional.
// - LabelRight: The text label for the toggle. Optional.
// - Checked: Controls the checked state. Can be bool or string for Alpine.js binding. Optional.
// - Disabled: Controls the disabled state. Can be bool or string for Alpine.js binding. Optional.
// - Class: Additional CSS classes. Optional.
// - Attributes: Additional HTML attributes. Optional.
// - ID: Unique identifier
// - Name: Form field name
// - LabelLeft: Text before toggle
// - LabelRight: Text after toggle
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
//
// Features:
// - Animated switching
// - Keyboard navigation
// - Label placement options
// - ARIA support
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
id={ props.ID }
type="checkbox"
name={ props.Name }
class="hidden"
if props.Checked != "" {
x-init={ "checked = " + props.Checked }
}
if props.Disabled != "" {
:disabled={ props.Disabled }
}
x-model="checked"
class="peer sr-only"
role="switch"
{ props.Attributes... }
/>
if props.LabelLeft != "" {
<label
@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
>
<span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
{ props.LabelLeft }
</label>
</span>
}
// FIX: Browser console bug: Alpine Expression Error: Unexpected token '}' -> on :disabled attribute -> But it works
<button
x-ref="switchButton"
type="button"
@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>
<div
class="relative h-6 w-10 rounded-full bg-neutral-200 after:h-5 after:w-5 peer-checked:after:translate-x-[16px] after:absolute after:left-0.5 after:top-0.5 after:rounded-full after:bg-muted-foreground after:transition-all after:content-[''] peer-checked:bg-primary peer-checked:after:bg-secondary peer-disabled:opacity-50 peer-disabled:cursor-not-allowed"
aria-hidden="true"
></div>
if props.LabelRight != "" {
<label
@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
>
<span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
{ props.LabelRight }
</label>
</span>
}
</div>
</label>
}

View File

@ -8,81 +8,49 @@ package components
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
// ToggleSize represents the size of the toggle
// / ToggleSize defines the available toggle dimensions
type ToggleSize string
// ToggleLabelPlacement represents where the label should be placed
// ToggleLabelPlacement defines label position options
type ToggleLabelPlacement string
// ToggleProps defines the properties for the Toggle component
type ToggleProps struct {
// ID is the unique identifier for the toggle input
// ID uniquely identifies the toggle
ID string
// Name is the name attribute for the toggle input
// Name sets the form field name
Name string
// Label is the text label for the toggle
// LabelLeft displays text before toggle
LabelLeft string
// Label is the text label for the toggle
// LabelRight displays text after toggle
LabelRight string
// It's treated as an Alpine.js expression for dynamic checking.
// 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 adds custom CSS classes
Class string
// Attributes allows passing additional HTML attributes
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Toggle renders a toggle switch component based on the provided props.
// It can be customized with different label placements, and supports
// both static and dynamic states through Alpine.js integration.
//
// 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",
// })
// Toggle renders a switch control for boolean values.
// Uses Alpine.js for state management and animations.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/toggle
//
// Props:
// - ID: The unique identifier for the toggle input. Required.
// - Name: The name attribute for the toggle input. Required.
// - LabelLeft: The text label for the toggle. Optional.
// - LabelRight: The text label for the toggle. Optional.
// - Checked: Controls the checked state. Can be bool or string for Alpine.js binding. Optional.
// - Disabled: Controls the disabled state. Can be bool or string for Alpine.js binding. Optional.
// - Class: Additional CSS classes. Optional.
// - Attributes: Additional HTML attributes. Optional.
// - ID: Unique identifier
// - Name: Form field name
// - LabelLeft: Text before toggle
// - LabelRight: Text after toggle
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
//
// Features:
// - Animated switching
// - Keyboard navigation
// - Label placement options
// - ARIA support
func Toggle(props ToggleProps) 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
@ -104,155 +72,100 @@ func Toggle(props ToggleProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
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 {
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/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))
if templ_7745c5c3_Err != nil {
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=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/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 {
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 {
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_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
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Disabled != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" :disabled=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("> ")
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 {
return templ_7745c5c3_Err
}
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 {
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))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
if props.LabelLeft != "" {
_, 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 props.LabelRight != "" {
_, 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 {
return templ_7745c5c3_Err
}
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 {
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))
if templ_7745c5c3_Err != nil {
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 {
return templ_7745c5c3_Err
}
}
var templ_7745c5c3_Var7 = []any{
"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>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -449,46 +449,47 @@ video {
:root {
--background: 0 0% 100%;
--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-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 72.22% 50.59%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 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;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--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%;
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--border: 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 {
position: static;
.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;
}
.fixed {
@ -670,6 +691,10 @@ body {
left: 0px;
}
.left-1\/2 {
left: 50%;
}
.left-full {
left: 100%;
}
@ -678,10 +703,22 @@ body {
right: 0px;
}
.right-3 {
right: 0.75rem;
}
.top-0 {
top: 0px;
}
.top-1\/2 {
top: 50%;
}
.top-3 {
top: 0.75rem;
}
.top-full {
top: 100%;
}
@ -698,6 +735,10 @@ body {
z-index: 50;
}
.m-0 {
margin: 0px;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@ -775,6 +816,16 @@ body {
aspect-ratio: 1 / 1;
}
.size-3 {
width: 0.75rem;
height: 0.75rem;
}
.size-4 {
width: 1rem;
height: 1rem;
}
.h-1\/2 {
height: 50%;
}
@ -795,6 +846,10 @@ body {
height: 4rem;
}
.h-2 {
height: 0.5rem;
}
.h-4 {
height: 1rem;
}
@ -827,6 +882,10 @@ body {
height: 100%;
}
.min-h-\[80px\] {
min-height: 80px;
}
.w-1\/3 {
width: 33.333333%;
}
@ -851,10 +910,6 @@ body {
width: 1rem;
}
.w-5 {
width: 1.25rem;
}
.w-56 {
width: 14rem;
}
@ -875,10 +930,6 @@ body {
width: 100%;
}
.max-w-md {
max-width: 28rem;
}
.flex-1 {
flex: 1 1 0%;
}
@ -887,11 +938,21 @@ body {
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 {
--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));
}
.-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 {
--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));
@ -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));
}
.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 {
--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));
@ -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));
}
.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 {
--tw-scale-x: 1;
--tw-scale-y: 1;
@ -962,6 +1008,10 @@ body {
user-select: none;
}
.resize {
resize: both;
}
.appearance-none {
-webkit-appearance: none;
-moz-appearance: none;
@ -1106,11 +1156,6 @@ body {
border-top-width: 1px;
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
}
.border-border {
--tw-border-opacity: 1;
border-color: hsl(var(--border) / var(--tw-border-opacity));
@ -1174,11 +1219,6 @@ body {
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 {
background-color: hsl(var(--muted) / 0.5);
}
@ -1262,11 +1302,6 @@ body {
padding-right: 2rem;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
@ -1459,10 +1494,6 @@ body {
opacity: 1;
}
.opacity-50 {
opacity: 0.5;
}
.opacity-80 {
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);
}
.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 {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@ -1520,6 +1545,11 @@ body {
--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: 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));
}
.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 {
--tw-border-opacity: 1;
border-color: hsl(var(--primary) / var(--tw-border-opacity));
@ -1634,6 +1765,17 @@ body {
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 {
--tw-bg-opacity: 1;
background-color: hsl(var(--accent) / var(--tw-bg-opacity));
@ -1698,6 +1840,22 @@ body {
outline-offset: 2px;
}
.focus\:outline:focus {
outline-style: solid;
}
.focus\:outline-2:focus {
outline-width: 2px;
}
.focus\:outline-offset-2:focus {
outline-offset: 2px;
}
.focus\:outline-ring:focus {
outline-color: hsl(var(--ring) / 1);
}
.focus\:ring-2:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -1713,6 +1871,19 @@ body {
--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 {
outline: 2px solid transparent;
outline-offset: 2px;
@ -1733,6 +1904,14 @@ body {
--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 {
pointer-events: none;
}
@ -1763,24 +1942,30 @@ body {
opacity: 1;
}
.peer:checked ~ .peer-checked\:visible {
visibility: visible;
}
.peer:checked ~ .peer-checked\:bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.peer:focus-visible ~ .peer-focus-visible\:ring-2 {
--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);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
.peer:checked ~ .peer-checked\:text-foreground {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.peer:focus-visible ~ .peer-focus-visible\:ring-ring {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
.peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
content: var(--tw-content);
--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 {
--tw-ring-offset-width: 2px;
.peer:checked ~ .peer-checked\:after\:bg-secondary::after {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
}
.peer:disabled ~ .peer-disabled\:cursor-not-allowed {
@ -1791,6 +1976,10 @@ body {
opacity: 0.5;
}
.peer:disabled ~ .peer-disabled\:opacity-70 {
opacity: 0.7;
}
.dark\:text-gray-200:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
@ -1820,10 +2009,6 @@ body {
height: 50%;
}
.sm\:max-w-\[70\%\] {
max-width: 70%;
}
.sm\:flex-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) {
padding-left: 2.75rem;
}

9950
repopack-output.txt Normal file

File diff suppressed because it is too large Load Diff