Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 64 additions & 22 deletions resources/views/calendar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,81 @@
@elseif($pollMillis !== null)
wire:poll.{{ $pollMillis }}ms
@endif
x-data="{ touchStartX: 0, touchStartY: 0 }"
x-on:touchstart="touchStartX = $event.touches[0].clientX; touchStartY = $event.touches[0].clientY"
x-on:touchend="
const dx = $event.changedTouches[0].clientX - touchStartX;
const dy = $event.changedTouches[0].clientY - touchStartY;
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) {
if (dx > 0) $wire.goToPreviousMonth();
else $wire.goToNextMonth();
}
"
>
<div>
<div class="md:hidden sticky top-0 z-10 bg-white/95 backdrop-blur-sm border-b border-gray-100">
<div class="h-11 px-2 flex items-center justify-between gap-2">
<button wire:click="goToPreviousMonth" class="min-h-[44px] min-w-[44px] flex items-center justify-center" aria-label="Previous month">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-gray-700" 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" />
</svg>
</button>

<button wire:click="goToCurrentMonth" class="text-base font-semibold text-gray-900">
{{ $startsAt->format('F Y') }}
</button>

<div class="flex items-center gap-2">
@if(!$startsAt->isSameMonth(now()))
<button wire:click="goToCurrentMonth" class="text-xs font-medium text-blue-600 border border-blue-200 rounded-full px-3 py-1">
Today
</button>
@endif

<button wire:click="goToNextMonth" class="min-h-[44px] min-w-[44px] flex items-center justify-center" aria-label="Next month">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-gray-700" 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" />
</svg>
</button>
</div>
</div>
</div>

<div class="hidden md:block">
@includeIf($beforeCalendarView)
</div>

<div class="flex">
<div class="overflow-x-auto w-full">
<div class="inline-block min-w-full overflow-hidden">
<div class="w-full">
<div class="w-full overflow-hidden">
<div class="w-full flex flex-row">
@foreach($monthGrid->first() as $day)
@include($dayOfWeekView, ['day' => $day])
@endforeach
</div>

@foreach($monthGrid as $week)
<div class="w-full flex flex-row">
@foreach($monthGrid->first() as $day)
@include($dayOfWeekView, ['day' => $day])
@foreach($week as $day)
@include($dayView, [
'componentId' => $componentId,
'day' => $day,
'dayInMonth' => $day->isSameMonth($startsAt),
'isToday' => $day->isToday(),
'events' => $getEventsForDay($day, $events),
])
@endforeach
</div>

@foreach($monthGrid as $week)
<div class="w-full flex flex-row">
@foreach($week as $day)
@include($dayView, [
'componentId' => $componentId,
'day' => $day,
'dayInMonth' => $day->isSameMonth($startsAt),
'isToday' => $day->isToday(),
'events' => $getEventsForDay($day, $events),
])
@endforeach
</div>
@endforeach
</div>
@endforeach
</div>
</div>

<div>
<div class="md:hidden border-t border-gray-100 mt-1" id="mobile-day-detail-panel" tabindex="-1">
@include('livewire-calendar::mobile-day-detail', [
'day' => $selectedDay,
'events' => $selectedDay ? $getEventsForDay($selectedDay, $events) : collect(),
])
</div>

<div class="hidden md:block">
@includeIf($afterCalendarView)
</div>
</div>
11 changes: 5 additions & 6 deletions resources/views/day-of-week.blade.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<div class="flex-1 h-12 border -mt-px -ml-px flex items-center justify-center bg-indigo-100 text-gray-900"
style="min-width: 10rem;">

<p class="text-sm">
{{ $day->format('l') }}
<div class="flex-1 h-6 md:h-12 border -mt-px -ml-px flex items-center justify-center md:bg-indigo-100 text-gray-500 md:text-gray-900">
<p class="text-[10px] font-semibold uppercase tracking-wider md:text-sm md:font-normal md:tracking-normal md:normal-case">
<span class="md:hidden">{{ substr($day->format('l'), 0, 1) }}</span>
<span class="hidden md:inline lg:hidden">{{ $day->format('D') }}</span>
<span class="hidden lg:inline">{{ $day->format('l') }}</span>
</p>

</div>
59 changes: 34 additions & 25 deletions resources/views/day.blade.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

<div
x-data="{ dragOver: false }"
x-on:dragenter.prevent="dragOver = true"
x-on:dragleave.prevent="dragOver = false"
x-data="{ dragOver: false, dragAndDropTouchEnabled: window.innerWidth >= 768 }"
x-on:dragenter.prevent="if (dragAndDropTouchEnabled) dragOver = true"
x-on:dragleave.prevent="if (dragAndDropTouchEnabled) dragOver = false"
x-on:dragover.prevent
x-on:drop.prevent="
if (!dragAndDropTouchEnabled) return;
dragOver = false;
$wire.onEventDropped(
$event.dataTransfer.getData('id'),
Expand All @@ -14,50 +14,59 @@
)
"
:class="{ '{{ $dragAndDropClasses }}': dragOver }"
class="flex-1 h-40 lg:h-48 border border-gray-200 -mt-px -ml-px"
style="min-width: 10rem;">

{{-- Wrapper for Drag and Drop --}}
<div
class="w-full h-full"
id="{{ $componentId }}-{{ $day }}">

class="flex-1 h-10 md:h-40 lg:h-48 border border-gray-200 -mt-px -ml-px"
>
<div class="w-full h-full" id="{{ $componentId }}-{{ $day }}">
<div
@if($dayClickEnabled)
wire:click="onDayClick({{ $day->year }}, {{ $day->month }}, {{ $day->day }})"
role="gridcell"
aria-selected="{{ $selectedDay && $selectedDay->isSameDay($day) ? 'true' : 'false' }}"
@endif
class="w-full h-full p-2 {{ $dayInMonth ? $isToday ? 'bg-yellow-100' : ' bg-white ' : 'bg-gray-100' }} flex flex-col">
class="w-full h-full p-0.5 md:p-2 flex flex-col {{ $dayInMonth ? '' : 'opacity-30 md:opacity-100 md:bg-gray-100' }} {{ $dayInMonth ? ($isToday ? 'md:bg-yellow-100' : 'bg-white') : '' }} {{ $selectedDay && $selectedDay->isSameDay($day) ? 'bg-blue-50 md:bg-inherit' : '' }}"
>
<div class="flex items-center justify-center md:justify-start">
<span class="md:hidden text-xs {{ $dayInMonth ? 'font-medium' : '' }} {{ $isToday ? 'bg-blue-600 text-white rounded-full w-6 h-6 flex items-center justify-center font-semibold' : '' }}">
{{ $day->format('j') }}
</span>

{{-- Number of Day --}}
<div class="flex items-center">
<p class="text-sm {{ $dayInMonth ? ' font-medium ' : '' }}">
<p class="hidden md:block text-sm {{ $dayInMonth ? 'font-medium' : '' }}">
{{ $day->format('j') }}
</p>
<p class="text-xs text-gray-600 ml-4">

<p class="hidden md:block text-xs text-gray-600 ml-4">
@if($events->isNotEmpty())
{{ $events->count() }} {{ Str::plural('event', $events->count()) }}
@endif
</p>
</div>

{{-- Events --}}
<div class="p-2 my-2 flex-1 overflow-y-auto">
@if($events->isNotEmpty())
<div class="flex items-center gap-0.5 justify-center mt-0.5 md:hidden">
@foreach($events->take(3) as $event)
<div class="w-1 h-1 rounded-full bg-blue-500"></div>
@endforeach
@if($events->count() > 3)
<span class="text-[8px] text-gray-500 leading-none">+{{ $events->count() - 3 }}</span>
@endif
<span class="sr-only">{{ $events->count() }} {{ Str::plural('event', $events->count()) }}</span>
</div>
@endif

<div class="hidden md:block p-2 my-2 flex-1 overflow-y-auto">
<div class="grid grid-cols-1 grid-flow-row gap-2">
@foreach($events as $event)
<div
@if($dragAndDropEnabled && !($event['is_multiday'] ?? false))
draggable="true"
x-on:dragstart="$event.dataTransfer.setData('id', '{{ $event['id'] }}')"
x-bind:draggable="dragAndDropTouchEnabled"
x-on:dragstart="if (dragAndDropTouchEnabled) $event.dataTransfer.setData('id', '{{ $event['id'] }}')"
@endif
>
@include($eventView, [
'event' => $event,
])
@include($eventView, ['event' => $event])
</div>
@endforeach
</div>
</div>

</div>
</div>
</div>
42 changes: 42 additions & 0 deletions resources/views/mobile-day-detail.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@if($day)
<div class="p-3 space-y-3">
<p class="text-sm font-semibold text-gray-900">
{{ $day->format('l, M j') }}
</p>

@if($events->isEmpty())
<p class="text-sm text-gray-400">No events</p>
@else
<div class="space-y-2 max-h-80 overflow-y-auto">
@foreach($events as $event)
<div
@if($eventClickEnabled)
wire:click.stop="onEventClick('{{ $event['id'] }}')"
@endif
class="flex items-start gap-3 p-3 rounded-lg bg-white border border-gray-100 active:bg-gray-50 transition-colors cursor-pointer"
>
<div class="w-1 self-stretch rounded-full bg-blue-500 flex-shrink-0"></div>

<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">{{ $event['title'] }}</p>

@if(($event['is_multiday'] ?? false))
<p class="text-[10px] text-gray-400 mt-0.5">
Day {{ $event['day_position'] ?? 1 }} of {{ $event['total_days'] ?? 1 }}
</p>
@endif

@if(isset($event['start_time']) || isset($event['end_time']))
<p class="text-xs text-gray-500 mt-0.5">
{{ $event['start_time'] ?? 'All day' }}@if(isset($event['end_time'])) – {{ $event['end_time'] }}@endif
</p>
@endif
</div>
</div>
@endforeach
</div>
@endif
</div>
@else
<div class="p-4 text-center text-sm text-gray-400">Tap a day to see events</div>
@endif
12 changes: 11 additions & 1 deletion src/LivewireCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ class LivewireCalendar extends Component
public $dragAndDropEnabled;
public $dayClickEnabled;
public $eventClickEnabled;
public $selectedDay;

protected $casts = [
'startsAt' => 'date',
'endsAt' => 'date',
'gridStartsAt' => 'date',
'gridEndsAt' => 'date',
'selectedDay' => 'date',
];

public function mount($initialYear = null,
Expand Down Expand Up @@ -107,6 +109,8 @@ public function mount($initialYear = null,
$this->dayClickEnabled = $dayClickEnabled;
$this->eventClickEnabled = $eventClickEnabled;

$this->selectedDay = Carbon::today()->startOfDay();

$this->afterMount($extras);
}

Expand Down Expand Up @@ -157,6 +161,7 @@ public function goToCurrentMonth()
{
$this->startsAt = Carbon::today()->startOfMonth()->startOfDay();
$this->endsAt = $this->startsAt->clone()->endOfMonth()->startOfDay();
$this->selectedDay = Carbon::today()->startOfDay();

$this->calculateGridStartsEnds();
}
Expand Down Expand Up @@ -270,9 +275,14 @@ protected function enrichEventForDay(array $event, Carbon $day): array
return $event;
}

public function selectDay($year, $month, $day)
{
$this->selectedDay = Carbon::createFromDate($year, $month, $day)->startOfDay();
}

public function onDayClick($year, $month, $day)
{
//
$this->selectDay($year, $month, $day);
}

public function onEventClick($eventId)
Expand Down