mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:41:09 +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}
|
{/each}
|
||||||
|
|
||||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||||
{#each getScheduledTasks() as task (task.id)}
|
{#if settingsStore.showTasksInCalendar}
|
||||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
{#each getScheduledTasks() as task (task.id)}
|
||||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||||
<TaskBlock
|
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||||
{task}
|
<TaskBlock
|
||||||
style={isTaskBeingDragged
|
{task}
|
||||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
style={isTaskBeingDragged
|
||||||
: isTaskBeingResized
|
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
: isTaskBeingResized
|
||||||
: getTaskStyle(task)}
|
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||||
{onTaskClick}
|
: getTaskStyle(task)}
|
||||||
onDragStart={handleTaskDragStart}
|
{onTaskClick}
|
||||||
onResizeStart={handleTaskResizeStart}
|
onDragStart={handleTaskDragStart}
|
||||||
isDragging={isTaskBeingDragged}
|
onResizeStart={handleTaskResizeStart}
|
||||||
isResizing={isTaskBeingResized}
|
isDragging={isTaskBeingDragged}
|
||||||
/>
|
isResizing={isTaskBeingResized}
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Overflow indicators for events outside visible time range -->
|
<!-- Overflow indicators for events outside visible time range -->
|
||||||
{#if overflowEvents.before.length > 0}
|
{#if overflowEvents.before.length > 0}
|
||||||
|
|
|
||||||
|
|
@ -976,37 +976,39 @@
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
{#if settingsStore.showTasksInCalendar}
|
||||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||||
{@const isTaskCrossDayDrag =
|
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||||
isTaskBeingDragged &&
|
{@const isTaskCrossDayDrag =
|
||||||
taskDragTargetDay !== null &&
|
isTaskBeingDragged &&
|
||||||
!isSameDay(day, taskDragTargetDay)}
|
taskDragTargetDay !== null &&
|
||||||
<TaskBlock
|
!isSameDay(day, taskDragTargetDay)}
|
||||||
{task}
|
<TaskBlock
|
||||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
{task}
|
||||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||||
: isTaskBeingResized
|
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
: isTaskBeingResized
|
||||||
: getTaskStyle(task)}
|
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||||
{onTaskClick}
|
: getTaskStyle(task)}
|
||||||
onDragStart={handleTaskDragStart}
|
{onTaskClick}
|
||||||
onResizeStart={handleTaskResizeStart}
|
onDragStart={handleTaskDragStart}
|
||||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
onResizeStart={handleTaskResizeStart}
|
||||||
isResizing={isTaskBeingResized}
|
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||||
isDraggingSource={isTaskCrossDayDrag}
|
isResizing={isTaskBeingResized}
|
||||||
/>
|
isDraggingSource={isTaskCrossDayDrag}
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
|
||||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
<!-- 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)}
|
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||||
<TaskBlock
|
<TaskBlock
|
||||||
task={draggedTask}
|
task={draggedTask}
|
||||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||||
isDragging={true}
|
isDragging={true}
|
||||||
/>
|
/>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Drag preview (solid) for cross-day dragging - shows where event will be -->
|
<!-- Drag preview (solid) for cross-day dragging - shows where event will be -->
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
import { viewStore } from '$lib/stores/view.svelte';
|
import { viewStore } from '$lib/stores/view.svelte';
|
||||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||||
import { getOffsetDate } from '$lib/utils/dateNavigation';
|
import { getOffsetDate } from '$lib/utils/dateNavigation';
|
||||||
|
import { HOUR_HEIGHT_PX } from '$lib/utils/calendarConstants';
|
||||||
import WeekView from './WeekView.svelte';
|
import WeekView from './WeekView.svelte';
|
||||||
import DayView from './DayView.svelte';
|
import DayView from './DayView.svelte';
|
||||||
import MonthView from './MonthView.svelte';
|
import MonthView from './MonthView.svelte';
|
||||||
|
|
@ -37,6 +39,7 @@
|
||||||
|
|
||||||
// Container refs
|
// Container refs
|
||||||
let viewportEl: HTMLDivElement;
|
let viewportEl: HTMLDivElement;
|
||||||
|
let currentPageEl: HTMLDivElement;
|
||||||
let viewportWidth = $state(0);
|
let viewportWidth = $state(0);
|
||||||
|
|
||||||
// Threshold: 15% of viewport width or high velocity triggers navigation
|
// Threshold: 15% of viewport width or high velocity triggers navigation
|
||||||
|
|
@ -284,6 +287,39 @@
|
||||||
|
|
||||||
// Computed styles
|
// Computed styles
|
||||||
let trackStyle = $derived(`transform: translateX(calc(-33.333% + ${offsetX}px))`);
|
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>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
|
@ -331,7 +367,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Current View (main interactive view) -->
|
<!-- Current View (main interactive view) -->
|
||||||
<div class="carousel-page current">
|
<div class="carousel-page current" bind:this={currentPageEl}>
|
||||||
{#if viewStore.viewType === 'day'}
|
{#if viewStore.viewType === 'day'}
|
||||||
<DayView {onQuickCreate} {onEventClick} />
|
<DayView {onQuickCreate} {onEventClick} />
|
||||||
{:else if viewStore.viewType === '3day'}
|
{:else if viewStore.viewType === '3day'}
|
||||||
|
|
|
||||||
|
|
@ -1003,37 +1003,39 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Scheduled Tasks (Time-Blocking) -->
|
<!-- Scheduled Tasks (Time-Blocking) - only shown if enabled in settings -->
|
||||||
{#each getScheduledTasksForDay(day) as task (task.id)}
|
{#if settingsStore.showTasksInCalendar}
|
||||||
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
{#each getScheduledTasksForDay(day) as task (task.id)}
|
||||||
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
{@const isTaskBeingDragged = isTaskDragging && draggedTask?.id === task.id}
|
||||||
{@const isTaskCrossDayDrag =
|
{@const isTaskBeingResized = isTaskResizing && resizeTask?.id === task.id}
|
||||||
isTaskBeingDragged &&
|
{@const isTaskCrossDayDrag =
|
||||||
taskDragTargetDay !== null &&
|
isTaskBeingDragged &&
|
||||||
!isSameDay(day, taskDragTargetDay)}
|
taskDragTargetDay !== null &&
|
||||||
<TaskBlock
|
!isSameDay(day, taskDragTargetDay)}
|
||||||
{task}
|
<TaskBlock
|
||||||
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
{task}
|
||||||
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
style={isTaskBeingDragged && !isTaskCrossDayDrag
|
||||||
: isTaskBeingResized
|
? `top: ${taskDragPreviewTop}%; height: ${taskDragPreviewHeight}%;`
|
||||||
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
: isTaskBeingResized
|
||||||
: getTaskStyle(task)}
|
? `top: ${taskResizePreviewTop}%; height: ${taskResizePreviewHeight}%;`
|
||||||
{onTaskClick}
|
: getTaskStyle(task)}
|
||||||
onDragStart={handleTaskDragStart}
|
{onTaskClick}
|
||||||
onResizeStart={handleTaskResizeStart}
|
onDragStart={handleTaskDragStart}
|
||||||
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
onResizeStart={handleTaskResizeStart}
|
||||||
isResizing={isTaskBeingResized}
|
isDragging={isTaskBeingDragged && !isTaskCrossDayDrag}
|
||||||
isDraggingSource={isTaskCrossDayDrag}
|
isResizing={isTaskBeingResized}
|
||||||
/>
|
isDraggingSource={isTaskCrossDayDrag}
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
|
||||||
<!-- Task Drag preview (solid) for cross-day dragging - shows where task will be -->
|
<!-- 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)}
|
{#if isTaskDragging && draggedTask && taskDragTargetDay && isSameDay(day, taskDragTargetDay) && !getScheduledTasksForDay(day).some((t) => t.id === draggedTask!.id)}
|
||||||
<TaskBlock
|
<TaskBlock
|
||||||
task={draggedTask}
|
task={draggedTask}
|
||||||
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
style="top: {taskDragPreviewTop}%; height: {taskDragPreviewHeight}%;"
|
||||||
isDragging={true}
|
isDragging={true}
|
||||||
/>
|
/>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Drag preview (solid) for cross-day dragging - shows where event will be -->
|
<!-- 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;
|
showBirthdays: boolean;
|
||||||
showBirthdayAge: boolean;
|
showBirthdayAge: boolean;
|
||||||
|
|
||||||
|
// Task settings
|
||||||
|
showTasksInCalendar: boolean;
|
||||||
|
|
||||||
// UI settings
|
// UI settings
|
||||||
sidebarCollapsed: boolean;
|
sidebarCollapsed: boolean;
|
||||||
|
|
||||||
|
|
@ -96,6 +99,7 @@ const DEFAULT_SETTINGS: CalendarAppSettings = {
|
||||||
immersiveModeEnabled: false,
|
immersiveModeEnabled: false,
|
||||||
showBirthdays: true,
|
showBirthdays: true,
|
||||||
showBirthdayAge: true,
|
showBirthdayAge: true,
|
||||||
|
showTasksInCalendar: false,
|
||||||
sidebarCollapsed: false,
|
sidebarCollapsed: false,
|
||||||
quickViewPillViews: ['week', 'month', 'agenda'],
|
quickViewPillViews: ['week', 'month', 'agenda'],
|
||||||
customDayCount: 30,
|
customDayCount: 30,
|
||||||
|
|
@ -231,6 +235,9 @@ export const settingsStore = {
|
||||||
get showBirthdayAge() {
|
get showBirthdayAge() {
|
||||||
return baseStore.settings.showBirthdayAge;
|
return baseStore.settings.showBirthdayAge;
|
||||||
},
|
},
|
||||||
|
get showTasksInCalendar() {
|
||||||
|
return baseStore.settings.showTasksInCalendar;
|
||||||
|
},
|
||||||
get defaultEventDuration() {
|
get defaultEventDuration() {
|
||||||
return baseStore.settings.defaultEventDuration;
|
return baseStore.settings.defaultEventDuration;
|
||||||
},
|
},
|
||||||
|
|
@ -295,6 +302,10 @@ export const settingsStore = {
|
||||||
baseStore.set('selectedTagIds', []);
|
baseStore.set('selectedTagIds', []);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleTasksInCalendar() {
|
||||||
|
baseStore.set('showTasksInCalendar', !baseStore.settings.showTasksInCalendar);
|
||||||
|
},
|
||||||
|
|
||||||
// Time formatting helpers
|
// Time formatting helpers
|
||||||
formatTime(date: Date): string {
|
formatTime(date: Date): string {
|
||||||
if (baseStore.settings.timeFormat === '12h') {
|
if (baseStore.settings.timeFormat === '12h') {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue