@intinyagroup/calendar 0.1.1-alpha.17 → 0.1.1-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
- import { ChevronLeft, ChevronRight } from 'lucide-svelte';
3
- import { Button } from '@intinyagroup/ui';
4
- import { cn } from '@intinyagroup/ui/utils';
2
+ import { ChevronLeft, ChevronRight } from "lucide-svelte";
3
+ import { Button } from "@intinyagroup/ui";
4
+ import { cn } from "@intinyagroup/ui/utils";
5
5
 
6
6
  export type CalendarDate = { year: number; month: number; day: number };
7
7
 
@@ -25,13 +25,27 @@
25
25
  let viewYear = $state(value?.year ?? today.getFullYear());
26
26
  let viewMonth = $state(value?.month ?? today.getMonth());
27
27
 
28
- const monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];
29
- const dayNames = ['Su','Mo','Tu','We','Th','Fr','Sa'];
28
+ const monthNames = [
29
+ "January",
30
+ "February",
31
+ "March",
32
+ "April",
33
+ "May",
34
+ "June",
35
+ "July",
36
+ "August",
37
+ "September",
38
+ "October",
39
+ "November",
40
+ "December",
41
+ ];
42
+ const dayNames = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
30
43
  const daysInMonth = $derived(new Date(viewYear, viewMonth + 1, 0).getDate());
31
44
  const firstDayOfMonth = $derived(new Date(viewYear, viewMonth, 1).getDay());
32
45
 
33
46
  const calendarDays = $derived.by(() => {
34
- const days: { day: number; currentMonth: boolean; date: CalendarDate }[] = [];
47
+ const days: { day: number; currentMonth: boolean; date: CalendarDate }[] =
48
+ [];
35
49
  const prevMonthDays = new Date(viewYear, viewMonth, 0).getDate();
36
50
  for (let i = firstDayOfMonth - 1; i >= 0; i--) {
37
51
  const day = prevMonthDays - i;
@@ -40,7 +54,11 @@
40
54
  days.push({ day, currentMonth: false, date: { year, month, day } });
41
55
  }
42
56
  for (let day = 1; day <= daysInMonth; day++) {
43
- days.push({ day, currentMonth: true, date: { year: viewYear, month: viewMonth, day } });
57
+ days.push({
58
+ day,
59
+ currentMonth: true,
60
+ date: { year: viewYear, month: viewMonth, day },
61
+ });
44
62
  }
45
63
  const remaining = 42 - days.length;
46
64
  for (let day = 1; day <= remaining; day++) {
@@ -55,48 +73,142 @@
55
73
  return a?.year === b.year && a?.month === b.month && a?.day === b.day;
56
74
  }
57
75
  function isToday(date: CalendarDate) {
58
- return date.year === today.getFullYear() && date.month === today.getMonth() && date.day === today.getDate();
76
+ return (
77
+ date.year === today.getFullYear() &&
78
+ date.month === today.getMonth() &&
79
+ date.day === today.getDate()
80
+ );
59
81
  }
60
82
  function isDisabled(date: CalendarDate) {
61
- if (min && (date.year < min.year || (date.year === min.year && date.month < min.month) || (date.year === min.year && date.month === min.month && date.day < min.day))) return true;
62
- if (max && (date.year > max.year || (date.year === max.year && date.month > max.month) || (date.year === max.year && date.month === max.month && date.day > max.day))) return true;
83
+ if (
84
+ min &&
85
+ (date.year < min.year ||
86
+ (date.year === min.year && date.month < min.month) ||
87
+ (date.year === min.year &&
88
+ date.month === min.month &&
89
+ date.day < min.day))
90
+ )
91
+ return true;
92
+ if (
93
+ max &&
94
+ (date.year > max.year ||
95
+ (date.year === max.year && date.month > max.month) ||
96
+ (date.year === max.year &&
97
+ date.month === max.month &&
98
+ date.day > max.day))
99
+ )
100
+ return true;
63
101
  return false;
64
102
  }
65
- function prevMonth() { if (viewMonth === 0) { viewMonth = 11; viewYear--; } else { viewMonth--; } }
66
- function nextMonth() { if (viewMonth === 11) { viewMonth = 0; viewYear++; } else { viewMonth++; } }
67
- function selectDate(date: CalendarDate) { if (disabled || isDisabled(date)) return; value = date; onSelect?.(date); }
68
- function goToday() { viewYear = today.getFullYear(); viewMonth = today.getMonth(); selectDate({ year: today.getFullYear(), month: today.getMonth(), day: today.getDate() }); }
103
+ function prevMonth() {
104
+ if (viewMonth === 0) {
105
+ viewMonth = 11;
106
+ viewYear--;
107
+ } else {
108
+ viewMonth--;
109
+ }
110
+ }
111
+ function nextMonth() {
112
+ if (viewMonth === 11) {
113
+ viewMonth = 0;
114
+ viewYear++;
115
+ } else {
116
+ viewMonth++;
117
+ }
118
+ }
119
+ function selectDate(date: CalendarDate) {
120
+ if (disabled || isDisabled(date)) return;
121
+ value = date;
122
+ onSelect?.(date);
123
+ }
124
+ function goToday() {
125
+ viewYear = today.getFullYear();
126
+ viewMonth = today.getMonth();
127
+ selectDate({
128
+ year: today.getFullYear(),
129
+ month: today.getMonth(),
130
+ day: today.getDate(),
131
+ });
132
+ }
69
133
  </script>
70
134
 
71
- <div class={cn('inline-flex flex-col rounded-xl border border-[var(--ui-border)] bg-[var(--ui-card)] p-4 shadow-sm', className)}>
72
- <div class="flex items-center justify-between mb-4">
73
- <Button variant="ghost" size="sm" onclick={prevMonth} {disabled}><ChevronLeft class="size-4" /></Button>
74
- <div class="flex items-center gap-2">
75
- <span class="text-sm font-semibold text-[var(--ui-foreground)]">{monthNames[viewMonth]} {viewYear}</span>
76
- <Button variant="ghost" size="sm" onclick={goToday} {disabled} class="text-xs h-6 px-2">Today</Button>
135
+ <div
136
+ class={cn(
137
+ "inline-flex flex-col rounded-xl border border-[var(--ui-border)] bg-[var(--ui-card)] p-4 shadow-sm select-none",
138
+ className,
139
+ )}
140
+ style="min-width: 280px; max-width: 320px; box-sizing: border-box;"
141
+ >
142
+ <div
143
+ class="flex items-center justify-between mb-4"
144
+ style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem;"
145
+ >
146
+ <Button variant="ghost" size="sm" onclick={prevMonth} {disabled}
147
+ ><ChevronLeft class="size-4" /></Button
148
+ >
149
+ <div
150
+ class="flex items-center gap-2"
151
+ style="display: flex; align-items: center; gap: 0.5rem;"
152
+ >
153
+ <span class="text-sm font-semibold text-[var(--ui-foreground)]"
154
+ >{monthNames[viewMonth]} {viewYear}</span
155
+ >
156
+ <Button
157
+ variant="ghost"
158
+ size="sm"
159
+ onclick={goToday}
160
+ {disabled}
161
+ class="text-xs h-6 px-2">Today</Button
162
+ >
77
163
  </div>
78
- <Button variant="ghost" size="sm" onclick={nextMonth} {disabled}><ChevronRight class="size-4" /></Button>
164
+ <Button variant="ghost" size="sm" onclick={nextMonth} {disabled}
165
+ ><ChevronRight class="size-4" /></Button
166
+ >
79
167
  </div>
80
168
 
81
- <div class="grid grid-cols-7 gap-1 mb-2">
82
- {#each dayNames as d}<div class="text-center text-[11px] font-medium text-[var(--ui-muted-foreground)] py-1">{d}</div>{/each}
169
+ <div
170
+ class="grid grid-cols-7 gap-1 mb-2 text-center"
171
+ style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.25rem; margin-bottom: 0.5rem; text-align: center;"
172
+ >
173
+ {#each dayNames as d}
174
+ <div
175
+ class="text-center text-[11px] font-medium text-[var(--ui-muted-foreground)] py-1"
176
+ style="text-align: center; font-size: 0.6875rem; padding: 0.25rem 0;"
177
+ >
178
+ {d}
179
+ </div>
180
+ {/each}
83
181
  </div>
84
182
 
85
- <div class="grid grid-cols-7 gap-1">
86
- {#each calendarDays as { day, currentMonth, date } (date.year + '-' + date.month + '-' + date.day)}
183
+ <div
184
+ class="grid grid-cols-7 gap-1"
185
+ style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.25rem;"
186
+ >
187
+ {#each calendarDays as { day, currentMonth, date } (date.year + "-" + date.month + "-" + date.day)}
87
188
  {@const isSelected = isSameDate(value, date)}
88
189
  {@const isTodayDate = isToday(date)}
89
190
  {@const isDisabledDate = isDisabled(date)}
90
191
  <button
192
+ type="button"
91
193
  onclick={() => selectDate(date)}
92
194
  disabled={disabled || isDisabledDate}
195
+ style="width: 2.25rem; height: 2.25rem; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;"
93
196
  class="flex items-center justify-center size-9 rounded-lg text-sm transition-colors cursor-pointer
94
- {isSelected ? 'bg-[var(--ui-primary)] text-[var(--ui-primary-foreground)] font-semibold' : ''}
95
- {!isSelected && currentMonth ? 'text-[var(--ui-foreground)] hover:bg-[var(--ui-secondary)]' : ''}
96
- {!isSelected && !currentMonth ? 'text-[var(--ui-muted-foreground)]/40' : ''}
97
- {isTodayDate && !isSelected ? 'ring-2 ring-[var(--ui-primary)]/30 font-medium' : ''}
197
+ {isSelected
198
+ ? 'bg-[var(--ui-primary)] text-[var(--ui-primary-foreground)] font-semibold'
199
+ : ''}
200
+ {!isSelected && currentMonth
201
+ ? 'text-[var(--ui-foreground)] hover:bg-[var(--ui-secondary)]'
202
+ : ''}
203
+ {!isSelected && !currentMonth
204
+ ? 'text-[var(--ui-muted-foreground)]/40'
205
+ : ''}
206
+ {isTodayDate && !isSelected
207
+ ? 'ring-2 ring-[var(--ui-primary)]/30 font-medium'
208
+ : ''}
98
209
  {isDisabledDate || disabled ? 'opacity-40 cursor-not-allowed' : ''}"
99
- >{day}</button>
210
+ >{day}</button
211
+ >
100
212
  {/each}
101
213
  </div>
102
214
  </div>
@@ -1,7 +1,12 @@
1
1
  <script lang="ts">
2
- import { Calendar as CalendarIcon, ChevronLeft, ChevronRight, X } from 'lucide-svelte';
3
- import { Button } from '@intinyagroup/ui';
4
- import { cn } from '@intinyagroup/ui/utils';
2
+ import {
3
+ Calendar as CalendarIcon,
4
+ ChevronLeft,
5
+ ChevronRight,
6
+ X,
7
+ } from "lucide-svelte";
8
+ import { Button } from "@intinyagroup/ui";
9
+ import { cn } from "@intinyagroup/ui/utils";
5
10
  import {
6
11
  addMonths,
7
12
  subMonths,
@@ -16,9 +21,9 @@
16
21
  isSameMonth,
17
22
  isWithinInterval,
18
23
  isBefore,
19
- format
20
- } from 'date-fns';
21
- import { id as localeId, enUS as localeEn } from 'date-fns/locale';
24
+ format,
25
+ } from "date-fns";
26
+ import { id as localeId, enUS as localeEn } from "date-fns/locale";
22
27
 
23
28
  export type CalendarDate = { year: number; month: number; day: number };
24
29
  export type DateRange = {
@@ -36,8 +41,8 @@
36
41
  min = null,
37
42
  max = null,
38
43
  disabled = false,
39
- placeholder = 'Select date range...',
40
- locale = 'en-US',
44
+ placeholder = "Select date range...",
45
+ locale = "en-US",
41
46
  firstDayOfWeek = 0, // 0 = Sunday, 1 = Monday
42
47
  presets,
43
48
  class: className,
@@ -59,11 +64,15 @@
59
64
  const today = new Date();
60
65
 
61
66
  let viewDate = $state(
62
- value?.start ? new Date(value.start.year, value.start.month, value.start.day) : today
67
+ value?.start
68
+ ? new Date(value.start.year, value.start.month, value.start.day)
69
+ : today,
63
70
  );
64
71
  let hoverDate = $state<Date | null>(null);
65
72
 
66
- const activeDateFnsLocale = $derived(locale.startsWith('id') ? localeId : localeEn);
73
+ const activeDateFnsLocale = $derived(
74
+ locale.startsWith("id") ? localeId : localeEn,
75
+ );
67
76
  const weekStartsOn = $derived(firstDayOfWeek as 0 | 1 | 2 | 3 | 4 | 5 | 6);
68
77
 
69
78
  function toDate(d: CalendarDate | null): Date | null {
@@ -75,7 +84,7 @@
75
84
  return {
76
85
  year: date.getFullYear(),
77
86
  month: date.getMonth(),
78
- day: date.getDate()
87
+ day: date.getDate(),
79
88
  };
80
89
  }
81
90
 
@@ -83,7 +92,7 @@
83
92
  const dayNames = $derived.by(() => {
84
93
  const start = startOfWeek(viewDate, { weekStartsOn });
85
94
  return Array.from({ length: 7 }, (_, i) => {
86
- return format(addDays(start, i), 'EEE', { locale: activeDateFnsLocale });
95
+ return format(addDays(start, i), "EEE", { locale: activeDateFnsLocale });
87
96
  });
88
97
  });
89
98
 
@@ -98,7 +107,7 @@
98
107
  return days.map((d) => ({
99
108
  date: d,
100
109
  calendarDate: toCalendarDate(d),
101
- currentMonth: isSameMonth(d, viewDate)
110
+ currentMonth: isSameMonth(d, viewDate),
102
111
  }));
103
112
  });
104
113
 
@@ -112,9 +121,15 @@
112
121
  value = { start: toCalendarDate(date), end: null };
113
122
  } else if (startDateObj && !endDateObj) {
114
123
  if (isBefore(date, startDateObj)) {
115
- value = { start: toCalendarDate(date), end: toCalendarDate(startDateObj) };
124
+ value = {
125
+ start: toCalendarDate(date),
126
+ end: toCalendarDate(startDateObj),
127
+ };
116
128
  } else {
117
- value = { start: toCalendarDate(startDateObj), end: toCalendarDate(date) };
129
+ value = {
130
+ start: toCalendarDate(startDateObj),
131
+ end: toCalendarDate(date),
132
+ };
118
133
  }
119
134
  onSelect?.(value);
120
135
  isOpen = false;
@@ -131,8 +146,8 @@
131
146
 
132
147
  function formatDisplayDate(date: CalendarDate | null): string {
133
148
  const d = toDate(date);
134
- if (!d) return '';
135
- return format(d, 'dd/MM/yyyy', { locale: activeDateFnsLocale });
149
+ if (!d) return "";
150
+ return format(d, "dd/MM/yyyy", { locale: activeDateFnsLocale });
136
151
  }
137
152
 
138
153
  const label = $derived.by(() => {
@@ -159,51 +174,64 @@
159
174
 
160
175
  return [
161
176
  {
162
- label: 'Today',
163
- range: { start: toCalendarDate(today), end: toCalendarDate(today) }
177
+ label: "Today",
178
+ range: { start: toCalendarDate(today), end: toCalendarDate(today) },
164
179
  },
165
180
  {
166
- label: 'Next 7D',
167
- range: { start: toCalendarDate(today), end: toCalendarDate(addDays(today, 7)) }
181
+ label: "Next 7D",
182
+ range: {
183
+ start: toCalendarDate(today),
184
+ end: toCalendarDate(addDays(today, 7)),
185
+ },
168
186
  },
169
187
  {
170
- label: 'This Month',
171
- range: { start: toCalendarDate(startOfMonth(today)), end: toCalendarDate(endOfMonth(today)) }
188
+ label: "This Month",
189
+ range: {
190
+ start: toCalendarDate(startOfMonth(today)),
191
+ end: toCalendarDate(endOfMonth(today)),
192
+ },
172
193
  },
173
194
  {
174
- label: 'Last Month',
195
+ label: "Last Month",
175
196
  range: {
176
197
  start: toCalendarDate(startOfMonth(subMonths(today, 1))),
177
- end: toCalendarDate(endOfMonth(subMonths(today, 1)))
178
- }
198
+ end: toCalendarDate(endOfMonth(subMonths(today, 1))),
199
+ },
179
200
  },
180
201
  {
181
- label: 'YTD',
182
- range: { start: { year: y, month: 0, day: 1 }, end: toCalendarDate(today) }
183
- }
202
+ label: "YTD",
203
+ range: {
204
+ start: { year: y, month: 0, day: 1 },
205
+ end: toCalendarDate(today),
206
+ },
207
+ },
184
208
  ];
185
209
  });
186
210
  </script>
187
211
 
188
- <div class={cn('relative inline-block w-full max-w-sm', className)}>
212
+ <div class={cn("relative inline-block w-full max-w-sm", className)}>
189
213
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
190
214
  <div
191
215
  role="button"
192
216
  tabindex={disabled ? -1 : 0}
193
217
  aria-disabled={disabled}
194
- onclick={() => { if (!disabled) isOpen = !isOpen; }}
218
+ onclick={() => {
219
+ if (!disabled) isOpen = !isOpen;
220
+ }}
195
221
  onkeydown={(e) => {
196
222
  if (disabled) return;
197
- if (e.key === 'Enter' || e.key === ' ') {
223
+ if (e.key === "Enter" || e.key === " ") {
198
224
  e.preventDefault();
199
225
  isOpen = !isOpen;
200
226
  }
201
227
  }}
202
228
  class={cn(
203
- 'flex h-10 w-full items-center justify-between rounded-lg border border-[var(--ui-input)] bg-[var(--ui-background)] px-3 text-sm transition-colors text-left cursor-pointer select-none',
204
- 'hover:border-[var(--ui-border)] focus:outline-none focus:ring-2 focus:ring-[var(--ui-ring)]/20 focus:border-[var(--ui-primary)]',
205
- disabled && 'opacity-50 cursor-not-allowed pointer-events-none',
206
- value.start ? 'text-[var(--ui-foreground)]' : 'text-[var(--ui-muted-foreground)]'
229
+ "flex h-10 w-full items-center justify-between rounded-lg border border-[var(--ui-input)] bg-[var(--ui-background)] px-3 text-sm transition-colors text-left cursor-pointer select-none",
230
+ "hover:border-[var(--ui-border)] focus:outline-none focus:ring-2 focus:ring-[var(--ui-ring)]/20 focus:border-[var(--ui-primary)]",
231
+ disabled && "opacity-50 cursor-not-allowed pointer-events-none",
232
+ value.start
233
+ ? "text-[var(--ui-foreground)]"
234
+ : "text-[var(--ui-muted-foreground)]",
207
235
  )}
208
236
  >
209
237
  <div class="flex items-center gap-2 truncate">
@@ -237,37 +265,64 @@
237
265
  >
238
266
  <!-- Header controls -->
239
267
  <div class="flex items-center justify-between mb-3">
240
- <Button variant="ghost" size="sm" class="size-7 p-0" onclick={prevMonth}>
268
+ <Button
269
+ variant="ghost"
270
+ size="sm"
271
+ class="size-7 p-0"
272
+ onclick={prevMonth}
273
+ >
241
274
  <ChevronLeft class="size-4" />
242
275
  </Button>
243
- <span class="text-xs font-semibold text-[var(--ui-foreground)] capitalize">
244
- {format(viewDate, 'MMMM yyyy', { locale: activeDateFnsLocale })}
276
+ <span
277
+ class="text-xs font-semibold text-[var(--ui-foreground)] capitalize"
278
+ >
279
+ {format(viewDate, "MMMM yyyy", { locale: activeDateFnsLocale })}
245
280
  </span>
246
- <Button variant="ghost" size="sm" class="size-7 p-0" onclick={nextMonth}>
281
+ <Button
282
+ variant="ghost"
283
+ size="sm"
284
+ class="size-7 p-0"
285
+ onclick={nextMonth}
286
+ >
247
287
  <ChevronRight class="size-4" />
248
288
  </Button>
249
289
  </div>
250
290
 
251
291
  <!-- Day names -->
252
- <div class="grid grid-cols-7 mb-1 text-center">
292
+ <div
293
+ class="grid grid-cols-7 mb-1 text-center"
294
+ style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); text-align: center; margin-bottom: 0.25rem;"
295
+ >
253
296
  {#each dayNames as day}
254
- <span class="text-[11px] font-semibold text-[var(--ui-muted-foreground)] py-1 capitalize">
297
+ <span
298
+ class="text-[11px] font-semibold text-[var(--ui-muted-foreground)] py-1 capitalize"
299
+ style="text-align: center; font-size: 0.6875rem; padding: 0.25rem 0;"
300
+ >
255
301
  {day}
256
302
  </span>
257
303
  {/each}
258
304
  </div>
259
305
 
260
306
  <!-- Calendar grid -->
261
- <div class="grid grid-cols-7 gap-y-1">
307
+ <div
308
+ class="grid grid-cols-7 gap-y-1"
309
+ style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); row-gap: 0.25rem;"
310
+ >
262
311
  {#each calendarDays as { date, calendarDate, currentMonth }}
263
- {@const isStart = startDateObj ? isSameDay(startDateObj, date) : false}
312
+ {@const isStart = startDateObj
313
+ ? isSameDay(startDateObj, date)
314
+ : false}
264
315
  {@const isEnd = endDateObj ? isSameDay(endDateObj, date) : false}
265
316
  {@const activeRangeEnd = endDateObj || hoverDate}
266
317
  {@const inRange =
267
318
  startDateObj && activeRangeEnd
268
319
  ? isWithinInterval(date, {
269
- start: isBefore(startDateObj, activeRangeEnd) ? startDateObj : activeRangeEnd,
270
- end: isBefore(startDateObj, activeRangeEnd) ? activeRangeEnd : startDateObj
320
+ start: isBefore(startDateObj, activeRangeEnd)
321
+ ? startDateObj
322
+ : activeRangeEnd,
323
+ end: isBefore(startDateObj, activeRangeEnd)
324
+ ? activeRangeEnd
325
+ : startDateObj,
271
326
  })
272
327
  : false}
273
328
  {@const isEdge = isStart || isEnd}
@@ -276,10 +331,16 @@
276
331
  role="gridcell"
277
332
  aria-selected={isEdge}
278
333
  class={cn(
279
- 'relative py-0.5 flex items-center justify-center',
280
- inRange && !isEdge && 'bg-[var(--ui-primary)]/10',
281
- isStart && activeRangeEnd && !isSameDay(startDateObj, activeRangeEnd) && 'rounded-l-md bg-[var(--ui-primary)]/10',
282
- isEnd && startDateObj && !isSameDay(startDateObj, endDateObj) && 'rounded-r-md bg-[var(--ui-primary)]/10'
334
+ "relative py-0.5 flex items-center justify-center",
335
+ inRange && !isEdge && "bg-[var(--ui-primary)]/10",
336
+ isStart &&
337
+ activeRangeEnd &&
338
+ !isSameDay(startDateObj, activeRangeEnd) &&
339
+ "rounded-l-md bg-[var(--ui-primary)]/10",
340
+ isEnd &&
341
+ startDateObj &&
342
+ !isSameDay(startDateObj, endDateObj) &&
343
+ "rounded-r-md bg-[var(--ui-primary)]/10",
283
344
  )}
284
345
  onmouseenter={() => {
285
346
  if (startDateObj && !endDateObj) hoverDate = date;
@@ -290,11 +351,15 @@
290
351
  disabled={!currentMonth}
291
352
  onclick={() => handleDateClick(date)}
292
353
  class={cn(
293
- 'size-8 rounded-md text-xs font-medium transition-colors flex items-center justify-center cursor-pointer',
294
- !currentMonth && 'opacity-20 cursor-default',
295
- currentMonth && !isEdge && !inRange && 'hover:bg-[var(--ui-secondary)] text-[var(--ui-foreground)]',
296
- inRange && !isEdge && 'text-[var(--ui-primary)] font-semibold',
297
- isEdge && 'bg-[var(--ui-primary)] text-[var(--ui-primary-foreground)] font-bold shadow-xs'
354
+ "size-8 rounded-md text-xs font-medium transition-colors flex items-center justify-center cursor-pointer",
355
+ !currentMonth && "opacity-20 cursor-default",
356
+ currentMonth &&
357
+ !isEdge &&
358
+ !inRange &&
359
+ "hover:bg-[var(--ui-secondary)] text-[var(--ui-foreground)]",
360
+ inRange && !isEdge && "text-[var(--ui-primary)] font-semibold",
361
+ isEdge &&
362
+ "bg-[var(--ui-primary)] text-[var(--ui-primary-foreground)] font-bold shadow-xs",
298
363
  )}
299
364
  >
300
365
  {date.getDate()}
@@ -304,7 +369,9 @@
304
369
  </div>
305
370
 
306
371
  <!-- Presets quick buttons bar -->
307
- <div class="flex flex-wrap items-center gap-1.5 border-t border-[var(--ui-border)] mt-3 pt-2.5">
372
+ <div
373
+ class="flex flex-wrap items-center gap-1.5 border-t border-[var(--ui-border)] mt-3 pt-2.5"
374
+ >
308
375
  {#each activePresets as preset}
309
376
  <button
310
377
  type="button"