First commit

This commit is contained in:
AlacrisDevs
2026-02-04 23:01:44 +02:00
commit cfec43f7ef
78 changed files with 9509 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
<script lang="ts">
import type { CalendarEvent } from '$lib/supabase/types';
import { getMonthDays, isSameDay } from '$lib/api/calendar';
interface Props {
events: CalendarEvent[];
onDateClick?: (date: Date) => void;
onEventClick?: (event: CalendarEvent) => void;
}
let { events, onDateClick, onEventClick }: Props = $props();
let currentDate = $state(new Date());
const today = new Date();
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const days = $derived(getMonthDays(currentDate.getFullYear(), currentDate.getMonth()));
function prevMonth() {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
}
function nextMonth() {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
}
function goToToday() {
currentDate = new Date();
}
function getEventsForDay(date: Date): CalendarEvent[] {
return events.filter((event) => {
const eventStart = new Date(event.start_time);
return isSameDay(eventStart, date);
});
}
function isCurrentMonth(date: Date): boolean {
return date.getMonth() === currentDate.getMonth();
}
const monthYear = $derived(
currentDate.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })
);
</script>
<div class="bg-surface rounded-xl p-4">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-semibold text-light">{monthYear}</h2>
<div class="flex items-center gap-2">
<button
class="px-3 py-1.5 text-sm text-light/60 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
onclick={goToToday}
>
Today
</button>
<button
class="p-2 text-light/60 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
onclick={prevMonth}
aria-label="Previous month"
>
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
class="p-2 text-light/60 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
onclick={nextMonth}
aria-label="Next month"
>
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</div>
</div>
<div class="grid grid-cols-7 gap-px bg-light/10 rounded-lg overflow-hidden">
{#each weekDays as day}
<div class="bg-dark px-2 py-2 text-center text-sm font-medium text-light/50">
{day}
</div>
{/each}
{#each days as day}
{@const dayEvents = getEventsForDay(day)}
{@const isToday = isSameDay(day, today)}
{@const inMonth = isCurrentMonth(day)}
<button
class="bg-dark min-h-[80px] p-1 text-left transition-colors hover:bg-light/5"
class:opacity-40={!inMonth}
onclick={() => onDateClick?.(day)}
>
<div class="flex items-center justify-center w-7 h-7 mb-1">
<span
class="text-sm {isToday
? 'bg-primary text-white rounded-full w-7 h-7 flex items-center justify-center'
: 'text-light/80'}"
>
{day.getDate()}
</span>
</div>
<div class="space-y-0.5">
{#each dayEvents.slice(0, 3) as event}
<button
class="w-full text-xs px-1 py-0.5 rounded truncate text-left"
style="background-color: {event.color ?? '#6366f1'}20; color: {event.color ?? '#6366f1'}"
onclick={(e) => {
e.stopPropagation();
onEventClick?.(event);
}}
>
{event.title}
</button>
{/each}
{#if dayEvents.length > 3}
<p class="text-xs text-light/40 px-1">+{dayEvents.length - 3} more</p>
{/if}
</div>
</button>
{/each}
</div>
</div>