mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-15 03:32:15 +01:00
Replace FullCalendar with custom calendar UI
This commit is contained in:
103
resources/js/packages/ui/src/FullCalendar/useActivityBoxes.ts
Normal file
103
resources/js/packages/ui/src/FullCalendar/useActivityBoxes.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { computed, type ComputedRef } from 'vue';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import type { ActivityPeriod, WindowActivityInPeriod } from './activityTypes';
|
||||
import type { CalendarSettings } from './calendarSettings';
|
||||
import type { ActivityBox } from './calendarTypes';
|
||||
import type { Ref } from 'vue';
|
||||
import { getLocalizedDayJs } from '../utils/time';
|
||||
|
||||
export function useActivityBoxes(params: {
|
||||
activityPeriods: () => ActivityPeriod[] | undefined;
|
||||
viewDays: ComputedRef<Dayjs[]>;
|
||||
calendarSettings: Ref<CalendarSettings>;
|
||||
minutesToPixels: (minutes: number) => number;
|
||||
}) {
|
||||
function formatActivityDuration(durationMinutes: number): string {
|
||||
const hours = Math.floor(durationMinutes / 60);
|
||||
const minutes = durationMinutes % 60;
|
||||
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
||||
}
|
||||
|
||||
function getActivityBoxLabel(box: ActivityBox): string {
|
||||
const periodStart = getLocalizedDayJs(box.period.start);
|
||||
const periodEnd = getLocalizedDayJs(box.period.end);
|
||||
const durationMinutes = Math.round(periodEnd.diff(periodStart, 'minute', true));
|
||||
const durationText = formatActivityDuration(durationMinutes);
|
||||
const status = box.isIdle ? 'Idling' : 'Active';
|
||||
return `${status} (${durationText})`;
|
||||
}
|
||||
|
||||
function getActivityBoxActivities(box: ActivityBox) {
|
||||
return box.period.windowActivities ?? [];
|
||||
}
|
||||
|
||||
function getActivityPercentage(count: number, total: number): string {
|
||||
if (total === 0) return '0';
|
||||
return ((count / total) * 100).toFixed(0);
|
||||
}
|
||||
|
||||
function getActivityText(activity: WindowActivityInPeriod): string {
|
||||
return activity.url ? `${activity.appName} - ${activity.url}` : activity.appName;
|
||||
}
|
||||
|
||||
const activityBoxes = computed<ActivityBox[]>(() => {
|
||||
const periods = params.activityPeriods();
|
||||
if (!periods || periods.length === 0) return [];
|
||||
|
||||
const s = params.calendarSettings.value;
|
||||
const startMin = s.startHour * 60;
|
||||
const endMin = s.endHour * 60;
|
||||
const boxes: ActivityBox[] = [];
|
||||
|
||||
for (const day of params.viewDays.value) {
|
||||
const dateStr = day.format('YYYY-MM-DD');
|
||||
const dayStart = day.startOf('day');
|
||||
const dayEnd = day.endOf('day');
|
||||
|
||||
for (const period of periods) {
|
||||
const periodStart = getLocalizedDayJs(period.start);
|
||||
const periodEnd = getLocalizedDayJs(period.end);
|
||||
|
||||
if (periodEnd.isBefore(dayStart) || periodStart.isAfter(dayEnd)) continue;
|
||||
|
||||
const actualStart = periodStart.isAfter(dayStart) ? periodStart : dayStart;
|
||||
const actualEnd = periodEnd.isBefore(dayEnd) ? periodEnd : dayEnd;
|
||||
|
||||
const actualStartMin = actualStart.hour() * 60 + actualStart.minute();
|
||||
const actualEndMin = actualEnd.hour() * 60 + actualEnd.minute();
|
||||
|
||||
const clampedStart = Math.max(actualStartMin, startMin);
|
||||
const clampedEnd = Math.min(actualEndMin, endMin);
|
||||
|
||||
if (clampedEnd <= clampedStart) continue;
|
||||
|
||||
const top = params.minutesToPixels(clampedStart - startMin);
|
||||
const height = params.minutesToPixels(clampedEnd - clampedStart);
|
||||
|
||||
if (height > 0) {
|
||||
boxes.push({ dateStr, top, height, isIdle: period.isIdle, period });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return boxes;
|
||||
});
|
||||
|
||||
function activityBoxesForDay(dateStr: string): ActivityBox[] {
|
||||
return activityBoxes.value.filter((b) => b.dateStr === dateStr);
|
||||
}
|
||||
|
||||
function dayHasActivityStatus(dateStr: string): boolean {
|
||||
return activityBoxes.value.some((b) => b.dateStr === dateStr);
|
||||
}
|
||||
|
||||
return {
|
||||
activityBoxes,
|
||||
activityBoxesForDay,
|
||||
dayHasActivityStatus,
|
||||
getActivityBoxLabel,
|
||||
getActivityBoxActivities,
|
||||
getActivityPercentage,
|
||||
getActivityText,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user