mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:01:08 +02:00
🚸 feat(calendar): hide tasks by default and scroll to midday on load
- Add showTasksInCalendar setting (default: false) to hide task blocks - Auto-scroll time-grid views to 12:00 on initial load for better UX - Tasks can be re-enabled via settings toggle
This commit is contained in:
parent
5c19500748
commit
bd9bd556f4
5 changed files with 132 additions and 79 deletions
|
|
@ -813,24 +813,26 @@
|
|||
/>
|
||||
{/each}
|
||||
|
||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
||||
{#each getScheduledTasks() as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged}
|
||||
isResizing={isTaskBeingResized}
|
||||
/>
|
||||
{/each}
|
||||
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||
{#if settingsStore.showTasksInCalendar}
|
||||
{#each getScheduledTasks() as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged}
|
||||
isResizing={isTaskBeingResized}
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<!-- Overflow indicators for events outside visible time range -->
|
||||
{#if overflowEvents.before.length > 0}
|
||||
|
|
|
|||
|
|
@ -976,37 +976,39 @@
|
|||
</div>
|
||||
{/each}
|
||||
|
||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
{@const isTaskCrossDayDrag =
|
||||
isTaskBeingDragged &&
|
||||
taskDragTargetDay !== null &&
|
||||
!isSameDay(day, taskDragTargetDay)}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||
isResizing={isTaskBeingResized}
|
||||
isDraggingSource={isTaskCrossDayDrag}
|
||||
/>
|
||||
{/each}
|
||||
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||
{#if settingsStore.showTasksInCalendar}
|
||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
{@const isTaskCrossDayDrag =
|
||||
isTaskBeingDragged &&
|
||||
taskDragTargetDay !== null &&
|
||||
!isSameDay(day, taskDragTargetDay)}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||
isResizing={isTaskBeingResized}
|
||||
isDraggingSource={isTaskCrossDayDrag}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
||||
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||
<TaskBlock
|
||||
task={draggedTask}
|
||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||
isDragging={true}
|
||||
/>
|
||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
||||
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||
<TaskBlock
|
||||
task={draggedTask}
|
||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||
isDragging={true}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<!-- Drag preview (solid) for cross-day dragging - shows where event will be -->
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import { onMount } from 'svelte';
|
||||
import { viewStore } from '$lib/stores/view.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { getOffsetDate } from '$lib/utils/dateNavigation';
|
||||
import { HOUR_HEIGHT_PX } from '$lib/utils/calendarConstants';
|
||||
import WeekView from './WeekView.svelte';
|
||||
import DayView from './DayView.svelte';
|
||||
import MonthView from './MonthView.svelte';
|
||||
|
|
@ -37,6 +39,7 @@
|
|||
|
||||
// Container refs
|
||||
let viewportEl: HTMLDivElement;
|
||||
let currentPageEl: HTMLDivElement;
|
||||
let viewportWidth = $state(0);
|
||||
|
||||
// Threshold: 15% of viewport width or high velocity triggers navigation
|
||||
|
|
@ -284,6 +287,39 @@
|
|||
|
||||
// Computed styles
|
||||
let trackStyle = $derived(`transform: translateX(calc(-33.333% + ${offsetX}px))`);
|
||||
|
||||
// Scroll to center of day (around 12:00) on initial mount
|
||||
// Only for time-grid views (day, week, multi-day)
|
||||
onMount(() => {
|
||||
if (!browser) return;
|
||||
|
||||
// Small delay to ensure views are rendered
|
||||
setTimeout(() => {
|
||||
if (!currentPageEl) return;
|
||||
|
||||
// Only scroll for time-grid views (not month, year, agenda)
|
||||
const timeGridViews = [
|
||||
'day',
|
||||
'3day',
|
||||
'5day',
|
||||
'week',
|
||||
'10day',
|
||||
'14day',
|
||||
'30day',
|
||||
'60day',
|
||||
'90day',
|
||||
'365day',
|
||||
'custom',
|
||||
];
|
||||
if (!timeGridViews.includes(viewStore.viewType)) return;
|
||||
|
||||
// Calculate scroll position to center around 12:00 (noon)
|
||||
const targetHour = 12;
|
||||
const targetScrollTop = targetHour * HOUR_HEIGHT_PX - currentPageEl.clientHeight / 2;
|
||||
|
||||
currentPageEl.scrollTop = Math.max(0, targetScrollTop);
|
||||
}, 150);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
|
|
@ -331,7 +367,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Current View (main interactive view) -->
|
||||
<div class="carousel-page current">
|
||||
<div class="carousel-page current" bind:this={currentPageEl}>
|
||||
{#if viewStore.viewType === 'day'}
|
||||
<DayView {onQuickCreate} {onEventClick} />
|
||||
{:else if viewStore.viewType === '3day'}
|
||||
|
|
|
|||
|
|
@ -1003,37 +1003,39 @@
|
|||
/>
|
||||
{/each}
|
||||
|
||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
{@const isTaskCrossDayDrag =
|
||||
isTaskBeingDragged &&
|
||||
taskDragTargetDay !== null &&
|
||||
!isSameDay(day, taskDragTargetDay)}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||
isResizing={isTaskBeingResized}
|
||||
isDraggingSource={isTaskCrossDayDrag}
|
||||
/>
|
||||
{/each}
|
||||
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||
{#if settingsStore.showTasksInCalendar}
|
||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||
{@const isTaskCrossDayDrag =
|
||||
isTaskBeingDragged &&
|
||||
taskDragTargetDay !== null &&
|
||||
!isSameDay(day, taskDragTargetDay)}
|
||||
<TaskBlock
|
||||
{task}
|
||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||
: isTaskBeingResized
|
||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||
: getTaskStyle(task)}
|
||||
{onTaskClick}
|
||||
onDragStart={handleTaskDragStart}
|
||||
onResizeStart={handleTaskResizeStart}
|
||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||
isResizing={isTaskBeingResized}
|
||||
isDraggingSource={isTaskCrossDayDrag}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
||||
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||
<TaskBlock
|
||||
task={draggedTask}
|
||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||
isDragging={true}
|
||||
/>
|
||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
||||
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||
<TaskBlock
|
||||
task={draggedTask}
|
||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||
isDragging={true}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<!-- Drag preview (solid) for cross-day dragging - shows where event will be -->
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ export interface CalendarAppSettings extends Record<string, unknown> {
|
|||
showBirthdays: boolean;
|
||||
showBirthdayAge: boolean;
|
||||
|
||||
// Task settings
|
||||
showTasksInCalendar: boolean;
|
||||
|
||||
// UI settings
|
||||
sidebarCollapsed: boolean;
|
||||
|
||||
|
|
@ -96,6 +99,7 @@ const DEFAULT_SETTINGS: CalendarAppSettings = {
|
|||
immersiveModeEnabled: false,
|
||||
showBirthdays: true,
|
||||
showBirthdayAge: true,
|
||||
showTasksInCalendar: false,
|
||||
sidebarCollapsed: false,
|
||||
quickViewPillViews: ['week', 'month', 'agenda'],
|
||||
customDayCount: 30,
|
||||
|
|
@ -231,6 +235,9 @@ export const settingsStore = {
|
|||
get showBirthdayAge() {
|
||||
return baseStore.settings.showBirthdayAge;
|
||||
},
|
||||
get showTasksInCalendar() {
|
||||
return baseStore.settings.showTasksInCalendar;
|
||||
},
|
||||
get defaultEventDuration() {
|
||||
return baseStore.settings.defaultEventDuration;
|
||||
},
|
||||
|
|
@ -295,6 +302,10 @@ export const settingsStore = {
|
|||
baseStore.set('selectedTagIds', []);
|
||||
},
|
||||
|
||||
toggleTasksInCalendar() {
|
||||
baseStore.set('showTasksInCalendar', !baseStore.settings.showTasksInCalendar);
|
||||
},
|
||||
|
||||
// Time formatting helpers
|
||||
formatTime(date: Date): string {
|
||||
if (baseStore.settings.timeFormat === '12h') {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue