mirror of
https://github.com/axzilla/templui.git
synced 2025-02-21 00:32:58 +00:00
feat: add datepicker component
This commit is contained in:
parent
aea8a59b85
commit
48d807ce6a
@ -4,6 +4,7 @@
|
||||
|
||||
- Added: Input component
|
||||
- Added: Accordion component
|
||||
- Added: Datepicker component
|
||||
- Changed: Add button type prop
|
||||
- Changed: Use own input component on tabs example
|
||||
- Changed: Update all current components with library comments
|
||||
|
@ -759,6 +759,14 @@ body {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.mt-12 {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
@ -779,6 +787,10 @@ body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aspect-square {
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.h-1\/2 {
|
||||
height: 50%;
|
||||
}
|
||||
@ -819,6 +831,10 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-7 {
|
||||
height: 1.75rem;
|
||||
}
|
||||
|
||||
.\!max-h-\[501px\] {
|
||||
max-height: 501px !important;
|
||||
}
|
||||
@ -863,6 +879,14 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-7 {
|
||||
width: 1.75rem;
|
||||
}
|
||||
|
||||
.w-\[17rem\] {
|
||||
width: 17rem;
|
||||
}
|
||||
|
||||
.max-w-3xl {
|
||||
max-width: 48rem;
|
||||
}
|
||||
@ -883,6 +907,10 @@ body {
|
||||
max-width: 20rem;
|
||||
}
|
||||
|
||||
.max-w-lg {
|
||||
max-width: 32rem;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
@ -953,6 +981,10 @@ body {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.grid-cols-7 {
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -985,6 +1017,10 @@ body {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gap-1 {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-x-reverse: 0;
|
||||
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
|
||||
@ -1074,6 +1110,10 @@ body {
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
}
|
||||
|
||||
.rounded-full {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
@ -1104,6 +1144,14 @@ body {
|
||||
border-color: hsl(var(--input) / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-neutral-200\/70 {
|
||||
border-color: rgb(229 229 229 / 0.7);
|
||||
}
|
||||
|
||||
.border-transparent {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.bg-background {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: hsl(var(--background) / var(--tw-bg-opacity));
|
||||
@ -1148,6 +1196,35 @@ body {
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-blue-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-blue-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-neutral-200 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-neutral-800 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-opacity-75 {
|
||||
--tw-bg-opacity: 0.75;
|
||||
}
|
||||
|
||||
.bg-\[url\(\'\/assets\/img\/grid\.svg\'\)\] {
|
||||
background-image: url('/assets/img/grid.svg');
|
||||
}
|
||||
@ -1260,6 +1337,11 @@ body {
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.px-0\.5 {
|
||||
padding-left: 0.125rem;
|
||||
padding-right: 0.125rem;
|
||||
}
|
||||
|
||||
.pb-4 {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
@ -1340,6 +1422,10 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@ -1417,6 +1503,16 @@ body {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-gray-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-neutral-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(163 163 163 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
@ -1425,6 +1521,11 @@ body {
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
.antialiased {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
@ -1445,6 +1546,12 @@ body {
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow {
|
||||
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
@ -1493,6 +1600,10 @@ body {
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.duration-100 {
|
||||
transition-duration: 100ms;
|
||||
}
|
||||
|
||||
.ease-in {
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
||||
}
|
||||
@ -1501,6 +1612,10 @@ body {
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.ease-in-out {
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.\[mask-image\:linear-gradient\(180deg\2c white\2c rgba\(255\2c 255\2c 255\2c 0\)\)\] {
|
||||
-webkit-mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
|
||||
mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
|
||||
@ -1565,6 +1680,20 @@ body {
|
||||
background-color: hsl(var(--secondary) / 0.8);
|
||||
}
|
||||
|
||||
.hover\:bg-blue-100:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-neutral-200:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-opacity-75:hover {
|
||||
--tw-bg-opacity: 0.75;
|
||||
}
|
||||
|
||||
.hover\:text-accent-foreground:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--accent-foreground) / var(--tw-text-opacity));
|
||||
@ -1584,6 +1713,11 @@ body {
|
||||
color: hsl(var(--primary) / 0.8);
|
||||
}
|
||||
|
||||
.hover\:text-neutral-500:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(115 115 115 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:underline:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
@ -1614,6 +1748,20 @@ body {
|
||||
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-blue-500:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(59 130 246 / 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;
|
||||
}
|
||||
|
||||
.focus-visible\:outline-none:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
|
@ -27,6 +27,7 @@ func main() {
|
||||
mux.Handle("GET /docs/components/card", templ.Handler(pages.Card()))
|
||||
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
|
||||
mux.Handle("GET /docs/components/accordion", templ.Handler(pages.Accordion()))
|
||||
mux.Handle("GET /docs/components/datepicker", templ.Handler(pages.Datepicker()))
|
||||
|
||||
fmt.Println("Server is running on http://localhost:8090")
|
||||
http.ListenAndServe(":8090", mux)
|
||||
|
@ -41,6 +41,10 @@ var Sections = []Section{
|
||||
Text: "Card",
|
||||
Href: "/docs/components/card",
|
||||
},
|
||||
{
|
||||
Text: "Datepicker",
|
||||
Href: "/docs/components/datepicker",
|
||||
},
|
||||
{
|
||||
Text: "Input",
|
||||
Href: "/docs/components/input",
|
||||
|
212
internals/ui/components/datepicker.templ
Normal file
212
internals/ui/components/datepicker.templ
Normal file
@ -0,0 +1,212 @@
|
||||
package components
|
||||
|
||||
// DatepickerProps defines the properties for the Datepicker component.
|
||||
type DatepickerProps struct {
|
||||
// ID is the unique identifier for the datepicker input.
|
||||
ID string
|
||||
|
||||
// Name is the name attribute for the datepicker input.
|
||||
Name string
|
||||
|
||||
// Placeholder is the placeholder text for the datepicker input.
|
||||
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 string
|
||||
|
||||
// Class specifies additional CSS classes to apply to the datepicker container.
|
||||
Class string
|
||||
|
||||
// Attributes allows passing additional HTML attributes to the datepicker input element.
|
||||
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.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// @components.Datepicker(components.DatepickerProps{
|
||||
// ID: "my-datepicker",
|
||||
// Name: "selected-date",
|
||||
// Placeholder: "Select a date",
|
||||
// Format: "YYYY-MM-DD",
|
||||
// Class: "w-full",
|
||||
// })
|
||||
//
|
||||
// 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
|
||||
templ Datepicker(props DatepickerProps) {
|
||||
<div
|
||||
x-data="{
|
||||
datePickerOpen: false,
|
||||
datePickerValue: '',
|
||||
datePickerFormat: '{ templ.EscapeString(props.Format) }',
|
||||
datePickerMonth: '',
|
||||
datePickerYear: '',
|
||||
datePickerDay: '',
|
||||
datePickerDaysInMonth: [],
|
||||
datePickerBlankDaysInMonth: [],
|
||||
datePickerMonthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||||
datePickerDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||
datePickerDayClicked(day) {
|
||||
let selectedDate = new Date(this.datePickerYear, this.datePickerMonth, day);
|
||||
this.datePickerDay = day;
|
||||
this.datePickerValue = this.datePickerFormatDate(selectedDate);
|
||||
this.datePickerIsSelectedDate(day);
|
||||
this.datePickerOpen = false;
|
||||
},
|
||||
datePickerPreviousMonth(){
|
||||
if (this.datePickerMonth == 0) {
|
||||
this.datePickerYear--;
|
||||
this.datePickerMonth = 11;
|
||||
} else {
|
||||
this.datePickerMonth--;
|
||||
}
|
||||
this.datePickerCalculateDays();
|
||||
},
|
||||
datePickerNextMonth(){
|
||||
if (this.datePickerMonth == 11) {
|
||||
this.datePickerMonth = 0;
|
||||
this.datePickerYear++;
|
||||
} else {
|
||||
this.datePickerMonth++;
|
||||
}
|
||||
this.datePickerCalculateDays();
|
||||
},
|
||||
datePickerIsSelectedDate(day) {
|
||||
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
|
||||
return this.datePickerValue === this.datePickerFormatDate(d) ? true : false;
|
||||
},
|
||||
datePickerIsToday(day) {
|
||||
const today = new Date();
|
||||
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
|
||||
return today.toDateString() === d.toDateString() ? true : false;
|
||||
},
|
||||
datePickerCalculateDays() {
|
||||
let daysInMonth = new Date(this.datePickerYear, this.datePickerMonth + 1, 0).getDate();
|
||||
let dayOfWeek = new Date(this.datePickerYear, this.datePickerMonth).getDay();
|
||||
let blankdaysArray = [];
|
||||
for (var i = 1; i <= dayOfWeek; i++) {
|
||||
blankdaysArray.push(i);
|
||||
}
|
||||
let daysArray = [];
|
||||
for (var i = 1; i <= daysInMonth; i++) {
|
||||
daysArray.push(i);
|
||||
}
|
||||
this.datePickerBlankDaysInMonth = blankdaysArray;
|
||||
this.datePickerDaysInMonth = daysArray;
|
||||
},
|
||||
datePickerFormatDate(date) {
|
||||
let formattedDay = this.datePickerDays[date.getDay()];
|
||||
let formattedDate = ('0' + date.getDate()).slice(-2);
|
||||
let formattedMonth = this.datePickerMonthNames[date.getMonth()];
|
||||
let formattedMonthShortName = this.datePickerMonthNames[date.getMonth()].substring(0, 3);
|
||||
let formattedMonthInNumber = ('0' + (parseInt(date.getMonth()) + 1)).slice(-2);
|
||||
let formattedYear = date.getFullYear();
|
||||
|
||||
if (this.datePickerFormat === 'M d, Y') {
|
||||
return `${formattedMonthShortName} ${formattedDate}, ${formattedYear}`;
|
||||
}
|
||||
if (this.datePickerFormat === 'MM-DD-YYYY') {
|
||||
return `${formattedMonthInNumber}-${formattedDate}-${formattedYear}`;
|
||||
}
|
||||
if (this.datePickerFormat === 'DD-MM-YYYY') {
|
||||
return `${formattedDate}-${formattedMonthInNumber}-${formattedYear}`;
|
||||
}
|
||||
if (this.datePickerFormat === 'YYYY-MM-DD') {
|
||||
return `${formattedYear}-${formattedMonthInNumber}-${formattedDate}`;
|
||||
}
|
||||
if (this.datePickerFormat === 'D d M, Y') {
|
||||
return `${formattedDay} ${formattedDate} ${formattedMonthShortName} ${formattedYear}`;
|
||||
}
|
||||
|
||||
return `${formattedMonth} ${formattedDate}, ${formattedYear}`;
|
||||
},
|
||||
}"
|
||||
x-init="
|
||||
currentDate = new Date();
|
||||
datePickerMonth = currentDate.getMonth();
|
||||
datePickerYear = currentDate.getFullYear();
|
||||
datePickerDay = currentDate.getDate();
|
||||
datePickerValue = datePickerFormatDate(currentDate);
|
||||
datePickerCalculateDays();
|
||||
"
|
||||
class={ "relative", props.Class }
|
||||
x-cloak
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
id={ props.ID }
|
||||
name={ props.Name }
|
||||
placeholder={ props.Placeholder }
|
||||
x-model="datePickerValue"
|
||||
@click="datePickerOpen = !datePickerOpen"
|
||||
x-on:keydown.escape="datePickerOpen = false"
|
||||
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:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
readonly
|
||||
{ props.Attributes... }
|
||||
/>
|
||||
<div
|
||||
@click="datePickerOpen = !datePickerOpen"
|
||||
class="absolute top-0 right-0 px-3 py-2 cursor-pointer text-neutral-400 hover:text-neutral-500"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
x-show="datePickerOpen"
|
||||
x-transition
|
||||
@click.away="datePickerOpen = false"
|
||||
class="absolute top-0 left-0 max-w-lg p-4 mt-12 antialiased bg-white border rounded-lg shadow w-[17rem] border-neutral-200/70"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<span x-text="datePickerMonthNames[datePickerMonth]" class="text-lg font-bold text-gray-800"></span>
|
||||
<span x-text="datePickerYear" class="ml-1 text-lg font-normal text-gray-600"></span>
|
||||
</div>
|
||||
<div>
|
||||
<button @click="datePickerPreviousMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
|
||||
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
|
||||
</button>
|
||||
<button @click="datePickerNextMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
|
||||
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-7 mb-3">
|
||||
<template x-for="(day, index) in datePickerDays" :key="index">
|
||||
<div class="px-0.5">
|
||||
<div x-text="day" class="text-xs font-medium text-center text-gray-800"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="grid grid-cols-7">
|
||||
<template x-for="blankDay in datePickerBlankDaysInMonth">
|
||||
<div class="p-1 text-sm text-center border border-transparent"></div>
|
||||
</template>
|
||||
<template x-for="(day, dayIndex) in datePickerDaysInMonth" :key="dayIndex">
|
||||
<div class="px-0.5 mb-1 aspect-square">
|
||||
<div
|
||||
x-text="day"
|
||||
@click="datePickerDayClicked(day)"
|
||||
:class="{
|
||||
'bg-neutral-200': datePickerIsToday(day) == true,
|
||||
'text-gray-600 hover:bg-neutral-200': datePickerIsToday(day) == false && datePickerIsSelectedDate(day) == false,
|
||||
'bg-neutral-800 text-white hover:bg-opacity-75': datePickerIsSelectedDate(day) == true
|
||||
}"
|
||||
class="flex items-center justify-center text-sm leading-none text-center rounded-full cursor-pointer h-7 w-7"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
39
internals/ui/pages/datepicker.templ
Normal file
39
internals/ui/pages/datepicker.templ
Normal file
@ -0,0 +1,39 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"github.com/axzilla/goilerplate/internals/ui/components"
|
||||
"github.com/axzilla/goilerplate/internals/ui/layouts"
|
||||
"github.com/axzilla/goilerplate/internals/ui/showcase"
|
||||
)
|
||||
|
||||
templ Datepicker() {
|
||||
@layouts.DocsLayout() {
|
||||
<div>
|
||||
<div class="mb-16">
|
||||
<h1 class="text-3xl font-bold mb-2">Datepicker</h1>
|
||||
<p class="mb-4 text-muted-foreground">A date picker component.</p>
|
||||
</div>
|
||||
@components.Tabs(components.TabsProps{
|
||||
Tabs: []components.Tab{
|
||||
{
|
||||
ID: "preview",
|
||||
Title: "Preview",
|
||||
Content: showcase.DatepickerShowcase(),
|
||||
},
|
||||
{
|
||||
ID: "code",
|
||||
Title: "Code",
|
||||
Content: CodeSnippetFromEmbedded("datepicker.templ", "go", showcase.TemplFiles),
|
||||
},
|
||||
{
|
||||
ID: "component",
|
||||
Title: "Component",
|
||||
Content: CodeSnippetFromEmbedded("datepicker.templ", "go", components.TemplFiles),
|
||||
},
|
||||
},
|
||||
TabsContainerClass: "md:w-1/2",
|
||||
ContentContainerClass: "w-full",
|
||||
})
|
||||
</div>
|
||||
}
|
||||
}
|
17
internals/ui/showcase/datepicker.templ
Normal file
17
internals/ui/showcase/datepicker.templ
Normal file
@ -0,0 +1,17 @@
|
||||
package showcase
|
||||
|
||||
import (
|
||||
"github.com/axzilla/goilerplate/internals/ui/components"
|
||||
)
|
||||
|
||||
templ DatepickerShowcase() {
|
||||
<div class="flex justify-center items-center border rounded-md py-16 px-4">
|
||||
@components.Datepicker(components.DatepickerProps{
|
||||
ID: "my-datepicker",
|
||||
Name: "selected-date",
|
||||
Placeholder: "Select a date",
|
||||
Format: "YYYY-MM-DD",
|
||||
Class: "w-full max-w-xs",
|
||||
})
|
||||
</div>
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user