@intinyagroup/calendar 0.1.1-alpha.14 → 0.1.1-alpha.16
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.
- package/dist/EventCalendar.svelte +55 -28
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, CalendarDays, Clock, Plus, X } from 'lucide-svelte';
|
|
3
3
|
import { Button } from '@intinyagroup/ui';
|
|
4
4
|
import { cn } from '@intinyagroup/ui/utils';
|
|
5
5
|
import {
|
|
@@ -72,6 +72,23 @@
|
|
|
72
72
|
let dragCreateEnd = $state<{ date: Date; hour: number; minute: number } | null>(null);
|
|
73
73
|
let isDragCreating = $state(false);
|
|
74
74
|
let dragCreateColumn = $state<Date | null>(null);
|
|
75
|
+
// Mobile detection
|
|
76
|
+
let isMobile = $state(typeof window !== 'undefined' ? window.matchMedia('(max-width: 767px)').matches : false);
|
|
77
|
+
$effect(() => {
|
|
78
|
+
if (typeof window === 'undefined') return;
|
|
79
|
+
const mq = window.matchMedia('(max-width: 767px)');
|
|
80
|
+
isMobile = mq.matches;
|
|
81
|
+
const handler = (e: MediaQueryListEvent) => { isMobile = e.matches; };
|
|
82
|
+
mq.addEventListener('change', handler);
|
|
83
|
+
return () => mq.removeEventListener('change', handler);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Mobile week: show only current day ± 1
|
|
87
|
+
const mobileWeekDays = $derived([
|
|
88
|
+
subDays(currentDate, 1),
|
|
89
|
+
currentDate,
|
|
90
|
+
addDays(currentDate, 1)
|
|
91
|
+
]);
|
|
75
92
|
|
|
76
93
|
function isMultiDayOrAllDay(ev: CalendarEvent): boolean {
|
|
77
94
|
if (ev.allDay) return true;
|
|
@@ -390,8 +407,9 @@
|
|
|
390
407
|
return format(currentDate, 'MMMM yyyy', { locale: activeDateFnsLocale });
|
|
391
408
|
}
|
|
392
409
|
if (view === 'week') {
|
|
393
|
-
const
|
|
394
|
-
const
|
|
410
|
+
const displayDays = isMobile ? mobileWeekDays : weekDays;
|
|
411
|
+
const start = displayDays[0];
|
|
412
|
+
const end = displayDays[displayDays.length - 1];
|
|
395
413
|
const sStr = format(start, 'dd MMM', { locale: activeDateFnsLocale });
|
|
396
414
|
const eStr = format(end, 'dd MMM yyyy', { locale: activeDateFnsLocale });
|
|
397
415
|
return `${sStr} - ${eStr}`;
|
|
@@ -450,10 +468,10 @@
|
|
|
450
468
|
|
|
451
469
|
<div class={cn('relative flex flex-col rounded-xl border border-[var(--ui-border)] bg-[var(--ui-card)] shadow-xs overflow-hidden', className)}>
|
|
452
470
|
<!-- Toolbar Header -->
|
|
453
|
-
<div class="flex flex-
|
|
454
|
-
<div class="flex items-center gap-2">
|
|
471
|
+
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-[var(--ui-border)] p-4 sm:px-6">
|
|
472
|
+
<div class="flex flex-col sm:flex-row sm:items-center gap-2">
|
|
455
473
|
<h2 class="text-base font-bold text-[var(--ui-foreground)] capitalize">{titleHeader}</h2>
|
|
456
|
-
<div class="flex items-center gap-1
|
|
474
|
+
<div class="flex items-center gap-1">
|
|
457
475
|
<Button variant="outline" size="sm" class="size-8 p-0" onclick={goPrev}>
|
|
458
476
|
<ChevronLeft class="size-4" />
|
|
459
477
|
</Button>
|
|
@@ -464,7 +482,7 @@
|
|
|
464
482
|
<ChevronRight class="size-4" />
|
|
465
483
|
</Button>
|
|
466
484
|
</div>
|
|
467
|
-
<span class="inline-flex items-center rounded-md bg-[var(--ui-secondary)]/50 px-2 py-0.5 text-[10px] font-medium text-[var(--ui-muted-foreground)]">
|
|
485
|
+
<span class="hidden sm:inline-flex items-center rounded-md bg-[var(--ui-secondary)]/50 px-2 py-0.5 text-[10px] font-medium text-[var(--ui-muted-foreground)]">
|
|
468
486
|
{activeTimeZone}
|
|
469
487
|
</span>
|
|
470
488
|
</div>
|
|
@@ -476,37 +494,40 @@
|
|
|
476
494
|
type="button"
|
|
477
495
|
onclick={() => (view = 'month')}
|
|
478
496
|
class={cn(
|
|
479
|
-
'rounded-md px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
497
|
+
'rounded-md px-2 sm:px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
480
498
|
view === 'month' ? 'bg-[var(--ui-card)] text-[var(--ui-foreground)] shadow-xs' : 'text-[var(--ui-muted-foreground)] hover:text-[var(--ui-foreground)]'
|
|
481
499
|
)}
|
|
482
500
|
>
|
|
483
|
-
|
|
501
|
+
<CalendarDays class="size-4 sm:hidden" />
|
|
502
|
+
<span class="hidden sm:inline">Month</span>
|
|
484
503
|
</button>
|
|
485
504
|
<button
|
|
486
505
|
type="button"
|
|
487
506
|
onclick={() => (view = 'week')}
|
|
488
507
|
class={cn(
|
|
489
|
-
'rounded-md px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
508
|
+
'rounded-md px-2 sm:px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
490
509
|
view === 'week' ? 'bg-[var(--ui-card)] text-[var(--ui-foreground)] shadow-xs' : 'text-[var(--ui-muted-foreground)] hover:text-[var(--ui-foreground)]'
|
|
491
510
|
)}
|
|
492
511
|
>
|
|
493
|
-
|
|
512
|
+
<CalendarIcon class="size-4 sm:hidden" />
|
|
513
|
+
<span class="hidden sm:inline">Week</span>
|
|
494
514
|
</button>
|
|
495
515
|
<button
|
|
496
516
|
type="button"
|
|
497
517
|
onclick={() => (view = 'day')}
|
|
498
518
|
class={cn(
|
|
499
|
-
'rounded-md px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
519
|
+
'rounded-md px-2 sm:px-3 py-1 text-xs font-semibold transition-colors cursor-pointer',
|
|
500
520
|
view === 'day' ? 'bg-[var(--ui-card)] text-[var(--ui-foreground)] shadow-xs' : 'text-[var(--ui-muted-foreground)] hover:text-[var(--ui-foreground)]'
|
|
501
521
|
)}
|
|
502
522
|
>
|
|
503
|
-
|
|
523
|
+
<Clock class="size-4 sm:hidden" />
|
|
524
|
+
<span class="hidden sm:inline">Day</span>
|
|
504
525
|
</button>
|
|
505
526
|
</div>
|
|
506
527
|
|
|
507
528
|
{#if enableEventModal}
|
|
508
529
|
<Button size="sm" class="gap-1.5 h-8 text-xs" onclick={() => openCreateModal(currentDate)}>
|
|
509
|
-
<Plus class="size-3.5" /> Add Event
|
|
530
|
+
<Plus class="size-3.5" /> <span class="hidden sm:inline">Add Event</span>
|
|
510
531
|
</Button>
|
|
511
532
|
{/if}
|
|
512
533
|
</div>
|
|
@@ -540,7 +561,7 @@
|
|
|
540
561
|
handleEventDrop(date);
|
|
541
562
|
}}
|
|
542
563
|
class={cn(
|
|
543
|
-
'min-h-[110px] p-1.5 flex flex-col gap-1 transition-colors hover:bg-[var(--ui-secondary)]/25 cursor-pointer select-none',
|
|
564
|
+
'min-h-[80px] md:min-h-[110px] p-1 md:p-1.5 flex flex-col gap-1 transition-colors hover:bg-[var(--ui-secondary)]/25 cursor-pointer select-none',
|
|
544
565
|
!currentMonth && 'bg-[var(--ui-muted)]/15 opacity-50'
|
|
545
566
|
)}
|
|
546
567
|
>
|
|
@@ -562,7 +583,7 @@
|
|
|
562
583
|
|
|
563
584
|
<!-- Event pills with spanning indicator -->
|
|
564
585
|
<div class="flex flex-col gap-1 overflow-hidden">
|
|
565
|
-
{#each dayEvents.slice(0, 3) as ev (ev.id)}
|
|
586
|
+
{#each dayEvents.slice(0, isMobile ? 2 : 3) as ev (ev.id)}
|
|
566
587
|
{@const isSpanning = isMultiDayOrAllDay(ev)}
|
|
567
588
|
{@const isStartDay = isSameDay(new Date(ev.start), date)}
|
|
568
589
|
{@const isEndDay = isSameDay(new Date(ev.end), date)}
|
|
@@ -580,7 +601,7 @@
|
|
|
580
601
|
onEventClick?.(ev);
|
|
581
602
|
}}
|
|
582
603
|
class={cn(
|
|
583
|
-
'truncate px-1.5 py-0.5 text-left text-[11px] font-medium transition-opacity hover:opacity-85 text-white shadow-2xs cursor-grab active:cursor-grabbing',
|
|
604
|
+
'truncate px-1.5 py-0.5 text-left text-[10px] md:text-[11px] font-medium transition-opacity hover:opacity-85 text-white shadow-2xs cursor-grab active:cursor-grabbing',
|
|
584
605
|
isSpanning ? 'rounded-none' : 'rounded',
|
|
585
606
|
isSpanning && isStartDay && 'rounded-l-md',
|
|
586
607
|
isSpanning && isEndDay && 'rounded-r-md',
|
|
@@ -596,9 +617,9 @@
|
|
|
596
617
|
</button>
|
|
597
618
|
{/each}
|
|
598
619
|
|
|
599
|
-
{#if dayEvents.length > 3}
|
|
620
|
+
{#if dayEvents.length > (isMobile ? 2 : 3)}
|
|
600
621
|
<span class="text-[10px] font-semibold text-[var(--ui-muted-foreground)] px-1">
|
|
601
|
-
+{dayEvents.length - 3} more
|
|
622
|
+
+{dayEvents.length - (isMobile ? 2 : 3)} more
|
|
602
623
|
</span>
|
|
603
624
|
{/if}
|
|
604
625
|
</div>
|
|
@@ -607,11 +628,11 @@
|
|
|
607
628
|
</div>
|
|
608
629
|
{:else if view === 'week'}
|
|
609
630
|
<!-- WEEK VIEW -->
|
|
610
|
-
<div class="grid grid-cols-8 border-b border-[var(--ui-border)] bg-[var(--ui-secondary)]/20 text-center text-xs font-semibold text-[var(--ui-muted-foreground)] py-2">
|
|
631
|
+
<div class="grid grid-cols-4 md:grid-cols-8 border-b border-[var(--ui-border)] bg-[var(--ui-secondary)]/20 text-center text-xs font-semibold text-[var(--ui-muted-foreground)] py-2">
|
|
611
632
|
<div class="col-span-1">Time</div>
|
|
612
|
-
{#each weekDays as d
|
|
633
|
+
{#each (isMobile ? mobileWeekDays : weekDays) as d}
|
|
613
634
|
<div class="col-span-1 flex flex-col items-center">
|
|
614
|
-
<span class="capitalize">{
|
|
635
|
+
<span class="capitalize">{format(d, 'EEE', { locale: activeDateFnsLocale })}</span>
|
|
615
636
|
<span class={cn('size-6 flex items-center justify-center rounded-full text-xs mt-0.5', isToday(d) ? 'bg-[var(--ui-primary)] text-[var(--ui-primary-foreground)]' : '')}>
|
|
616
637
|
{d.getDate()}
|
|
617
638
|
</span>
|
|
@@ -620,13 +641,13 @@
|
|
|
620
641
|
</div>
|
|
621
642
|
|
|
622
643
|
<!-- All-day header slot (FullCalendar 1:1) -->
|
|
623
|
-
{@const allDayEvents = getAllDayEventsForWeek(weekDays)}
|
|
644
|
+
{@const allDayEvents = getAllDayEventsForWeek(isMobile ? mobileWeekDays : weekDays)}
|
|
624
645
|
{#if allDayEvents.length > 0}
|
|
625
|
-
<div class="grid grid-cols-8 border-b border-[var(--ui-border)] bg-[var(--ui-secondary)]/10 text-xs divide-x divide-[var(--ui-border)] py-1.5">
|
|
646
|
+
<div class="grid grid-cols-4 md:grid-cols-8 border-b border-[var(--ui-border)] bg-[var(--ui-secondary)]/10 text-xs divide-x divide-[var(--ui-border)] py-1.5">
|
|
626
647
|
<div class="col-span-1 text-right pr-2 text-[10px] uppercase tracking-wider font-semibold text-[var(--ui-muted-foreground)] flex items-center justify-end">
|
|
627
648
|
all-day
|
|
628
649
|
</div>
|
|
629
|
-
<div class="col-span-7 px-2 flex flex-col gap-1">
|
|
650
|
+
<div class="col-span-3 md:col-span-7 px-2 flex flex-col gap-1">
|
|
630
651
|
{#each allDayEvents as ev (ev.id)}
|
|
631
652
|
<button
|
|
632
653
|
type="button"
|
|
@@ -644,7 +665,7 @@
|
|
|
644
665
|
</div>
|
|
645
666
|
{/if}
|
|
646
667
|
|
|
647
|
-
<div class="grid grid-cols-8 divide-x divide-[var(--ui-border)] max-h-[600px] overflow-y-auto">
|
|
668
|
+
<div class="grid grid-cols-4 md:grid-cols-8 divide-x divide-[var(--ui-border)] max-h-[600px] overflow-y-auto">
|
|
648
669
|
<!-- Hours Column -->
|
|
649
670
|
<div class="col-span-1 divide-y divide-[var(--ui-border)]/50 text-right pr-2 text-[11px] font-medium text-[var(--ui-muted-foreground)]">
|
|
650
671
|
{#each hours as hour}
|
|
@@ -652,8 +673,8 @@
|
|
|
652
673
|
{/each}
|
|
653
674
|
</div>
|
|
654
675
|
|
|
655
|
-
<!--
|
|
656
|
-
{#each weekDays as d}
|
|
676
|
+
<!-- Day Grid Columns -->
|
|
677
|
+
{#each (isMobile ? mobileWeekDays : weekDays) as d}
|
|
657
678
|
{@const dayEvents = getTimedEventsForDay(d)}
|
|
658
679
|
{@const layoutEvents = computeOverlappingLayout(dayEvents)}
|
|
659
680
|
{@const isCurrentDay = isToday(d)}
|
|
@@ -755,6 +776,12 @@
|
|
|
755
776
|
</div>
|
|
756
777
|
{/each}
|
|
757
778
|
</div>
|
|
779
|
+
<!-- Mobile swipe hint -->
|
|
780
|
+
{#if isMobile}
|
|
781
|
+
<div class="px-4 py-2 text-center text-[11px] text-[var(--ui-muted-foreground)] border-t border-[var(--ui-border)]">
|
|
782
|
+
Swipe to see more days
|
|
783
|
+
</div>
|
|
784
|
+
{/if}
|
|
758
785
|
{:else}
|
|
759
786
|
<!-- DAY VIEW -->
|
|
760
787
|
<div class="p-3 border-b border-[var(--ui-border)] bg-[var(--ui-secondary)]/20 flex items-center justify-between">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intinyagroup/calendar",
|
|
3
|
-
"version": "0.1.1-alpha.
|
|
3
|
+
"version": "0.1.1-alpha.16",
|
|
4
4
|
"description": "Calendar and DatePicker components for intinyagroup UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "vitest run"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@intinyagroup/ui": "0.1.1-alpha.
|
|
23
|
+
"@intinyagroup/ui": "0.1.1-alpha.14",
|
|
24
24
|
"date-fns": "^4.4.0",
|
|
25
25
|
"lucide-svelte": "^1.0.1"
|
|
26
26
|
},
|