180 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			180 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import { html, type TemplateResult } from '@design.estate/dees-element'; | ||
|  | import type { DeesInputDatepicker } from './component.js'; | ||
|  | 
 | ||
|  | export const renderDatepicker = (component: DeesInputDatepicker): TemplateResult => { | ||
|  |       const monthNames = [ | ||
|  |         'January', 'February', 'March', 'April', 'May', 'June', | ||
|  |         'July', 'August', 'September', 'October', 'November', 'December' | ||
|  |       ]; | ||
|  | 
 | ||
|  |       const weekDays = component.weekStartsOn === 1  | ||
|  |         ? ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] | ||
|  |         : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']; | ||
|  | 
 | ||
|  |       const days = component.getDaysInMonth(); | ||
|  |       const isAM = component.selectedHour < 12; | ||
|  |       const timezones = component.getTimezones(); | ||
|  | 
 | ||
|  |       return html`
 | ||
|  |         <div class="input-wrapper"> | ||
|  |           <dees-label .label=${component.label} .description=${component.description} .required=${component.required}></dees-label> | ||
|  |           <div class="input-container"> | ||
|  |             <input | ||
|  |               type="text" | ||
|  |               class="date-input ${component.isOpened ? 'open' : ''}" | ||
|  |               .value=${component.formatDate(component.value)} | ||
|  |               .placeholder=${component.placeholder} | ||
|  |               ?disabled=${component.disabled} | ||
|  |               @click=${component.toggleCalendar} | ||
|  |               @keydown=${component.handleKeydown} | ||
|  |               @input=${component.handleManualInput} | ||
|  |               @blur=${component.handleInputBlur} | ||
|  |               style="padding-right: ${component.value ? '64px' : '40px'}" | ||
|  |             /> | ||
|  |             <div class="icon-container"> | ||
|  |               ${component.value && !component.disabled ? html`
 | ||
|  |                 <button class="clear-button" @click=${component.clearValue} title="Clear"> | ||
|  |                   <dees-icon icon="lucide:x" iconSize="14"></dees-icon> | ||
|  |                 </button> | ||
|  |               ` : ''}
 | ||
|  |               <dees-icon class="calendar-icon" icon="lucide:calendar" iconSize="16"></dees-icon> | ||
|  |             </div> | ||
|  |            | ||
|  |             <!-- Calendar Popup --> | ||
|  |             <div class="calendar-popup ${component.isOpened ? 'show' : ''} ${component.opensToTop ? 'top' : 'bottom'}"> | ||
|  |               <!-- Month/Year Navigation --> | ||
|  |               <div class="calendar-header"> | ||
|  |                 <button class="nav-button" @click=${component.previousMonth}> | ||
|  |                   <dees-icon icon="lucide:chevronLeft" iconSize="16"></dees-icon> | ||
|  |                 </button> | ||
|  |                 <div class="month-year-display"> | ||
|  |                   ${monthNames[component.viewDate.getMonth()]} ${component.viewDate.getFullYear()} | ||
|  |                 </div> | ||
|  |                 <button class="nav-button" @click=${component.nextMonth}> | ||
|  |                   <dees-icon icon="lucide:chevronRight" iconSize="16"></dees-icon> | ||
|  |                 </button> | ||
|  |               </div> | ||
|  | 
 | ||
|  |               <!-- Weekday Headers --> | ||
|  |               <div class="weekdays"> | ||
|  |                 ${weekDays.map(day => html`<div class="weekday">${day}</div>`)} | ||
|  |               </div> | ||
|  | 
 | ||
|  |               <!-- Days Grid --> | ||
|  |               <div class="days-grid"> | ||
|  |                 ${days.map(day => { | ||
|  |                   const isToday = component.isToday(day); | ||
|  |                   const isSelected = component.isSelected(day); | ||
|  |                   const isOtherMonth = day.getMonth() !== component.viewDate.getMonth(); | ||
|  |                   const isDisabled = component.isDisabled(day); | ||
|  |                   const dayEvents = component.getEventsForDate(day); | ||
|  |                   const hasEvents = dayEvents.length > 0; | ||
|  |                   const totalEventCount = dayEvents.reduce((sum, event) => sum + (event.count || 1), 0); | ||
|  | 
 | ||
|  |                   return html`
 | ||
|  |                     <div  | ||
|  |                       class="day ${isOtherMonth ? 'other-month' : ''} ${isToday ? 'today' : ''} ${isSelected ? 'selected' : ''} ${isDisabled ? 'disabled' : ''} ${hasEvents ? 'has-event' : ''}" | ||
|  |                       @click=${() => !isDisabled && component.selectDate(day)} | ||
|  |                     > | ||
|  |                       ${day.getDate()} | ||
|  |                       ${hasEvents ? html`
 | ||
|  |                         ${totalEventCount > 3 ? html`
 | ||
|  |                           <div class="event-count">${totalEventCount}</div> | ||
|  |                         ` : html` | ||
|  |                           <div class="event-indicator"> | ||
|  |                             ${dayEvents.slice(0, 3).map(event => html`
 | ||
|  |                               <div class="event-dot ${event.type || 'info'}"></div> | ||
|  |                             `)}
 | ||
|  |                           </div> | ||
|  |                         `}
 | ||
|  |                         ${dayEvents[0].title ? html`
 | ||
|  |                           <div class="event-tooltip"> | ||
|  |                             ${dayEvents[0].title} | ||
|  |                             ${totalEventCount > 1 ? html` (+${totalEventCount - 1} more)` : ''} | ||
|  |                           </div> | ||
|  |                         ` : ''}
 | ||
|  |                       ` : ''}
 | ||
|  |                     </div> | ||
|  |                   `;
 | ||
|  |                 })} | ||
|  |               </div> | ||
|  | 
 | ||
|  |               <!-- Time Selector --> | ||
|  |               ${component.enableTime ? html`
 | ||
|  |                 <div class="time-selector"> | ||
|  |                   <div class="time-selector-title">Time</div> | ||
|  |                   <div class="time-inputs"> | ||
|  |                     <input  | ||
|  |                       type="number"  | ||
|  |                       class="time-input"  | ||
|  |                       .value=${component.timeFormat === '12h'  | ||
|  |                         ? (component.selectedHour === 0 ? 12 : component.selectedHour > 12 ? component.selectedHour - 12 : component.selectedHour).toString().padStart(2, '0') | ||
|  |                         : component.selectedHour.toString().padStart(2, '0')} | ||
|  |                       @input=${(e: InputEvent) => component.handleHourInput(e)} | ||
|  |                       min="${component.timeFormat === '12h' ? 1 : 0}" | ||
|  |                       max="${component.timeFormat === '12h' ? 12 : 23}" | ||
|  |                     /> | ||
|  |                     <span class="time-separator">:</span> | ||
|  |                     <input  | ||
|  |                       type="number"  | ||
|  |                       class="time-input"  | ||
|  |                       .value=${component.selectedMinute.toString().padStart(2, '0')} | ||
|  |                       @input=${(e: InputEvent) => component.handleMinuteInput(e)} | ||
|  |                       min="0" | ||
|  |                       max="59" | ||
|  |                       step="${component.minuteIncrement || 1}" | ||
|  |                     /> | ||
|  |                     ${component.timeFormat === '12h' ? html`
 | ||
|  |                       <div class="am-pm-selector"> | ||
|  |                         <button  | ||
|  |                           class="am-pm-button ${isAM ? 'selected' : ''}" | ||
|  |                           @click=${() => component.setAMPM('am')} | ||
|  |                         > | ||
|  |                           AM | ||
|  |                         </button> | ||
|  |                         <button  | ||
|  |                           class="am-pm-button ${!isAM ? 'selected' : ''}" | ||
|  |                           @click=${() => component.setAMPM('pm')} | ||
|  |                         > | ||
|  |                           PM | ||
|  |                         </button> | ||
|  |                       </div> | ||
|  |                     ` : ''}
 | ||
|  |                   </div> | ||
|  |                 </div> | ||
|  |               ` : ''}
 | ||
|  | 
 | ||
|  |               <!-- Timezone Selector --> | ||
|  |               ${component.enableTimezone ? html`
 | ||
|  |                 <div class="timezone-selector"> | ||
|  |                   <div class="timezone-selector-title">Timezone</div> | ||
|  |                   <select  | ||
|  |                     class="timezone-select"  | ||
|  |                     .value=${component.timezone} | ||
|  |                     @change=${(e: Event) => component.handleTimezoneChange(e)} | ||
|  |                   > | ||
|  |                     ${timezones.map(tz => html`
 | ||
|  |                       <option value="${tz.value}" ?selected=${tz.value === component.timezone}> | ||
|  |                         ${tz.label} | ||
|  |                       </option> | ||
|  |                     `)}
 | ||
|  |                   </select> | ||
|  |                 </div> | ||
|  |               ` : ''}
 | ||
|  | 
 | ||
|  |               <!-- Action Buttons --> | ||
|  |               <div class="calendar-actions"> | ||
|  |                 <button class="action-button today-button" @click=${component.selectToday}> | ||
|  |                   Today | ||
|  |                 </button> | ||
|  |                 <button class="action-button clear-button" @click=${component.clear}> | ||
|  |                   Clear | ||
|  |                 </button> | ||
|  |               </div> | ||
|  |             </div> | ||
|  |           </div> | ||
|  |         </div> | ||
|  |       `;
 | ||
|  |    | ||
|  | }; |