fix(time-tracking) : keep calendar header sticky below page header
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-primary-500">Suivi des temps</h1>
|
||||
<button
|
||||
class="rounded-md bg-primary-500 px-4 py-2 text-sm font-semibold text-white hover:bg-primary-600 transition"
|
||||
@click="openCreateDrawer()"
|
||||
>
|
||||
+ Ajouter une Activité
|
||||
</button>
|
||||
</div>
|
||||
<div ref="pageHeaderEl" class="sticky top-0 z-40 bg-white pb-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-primary-500">Suivi des temps</h1>
|
||||
<button
|
||||
class="rounded-md bg-primary-500 px-4 py-2 text-sm font-semibold text-white hover:bg-primary-600 transition"
|
||||
@click="openCreateDrawer()"
|
||||
>
|
||||
+ Ajouter une Activité
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative z-30 mt-4 flex items-center gap-4">
|
||||
<div class="relative z-30 mt-4 flex items-center gap-4">
|
||||
<h2 class="text-lg font-bold text-orange-500">
|
||||
{{ currentMonthLabel }}
|
||||
</h2>
|
||||
@@ -62,6 +63,7 @@
|
||||
text-field="text-sm"
|
||||
text-value="text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
@@ -76,6 +78,7 @@
|
||||
:entries="filteredEntries"
|
||||
:start-date="startDate"
|
||||
:view-mode="viewMode"
|
||||
:sticky-offset="pageHeaderHeight"
|
||||
@edit-entry="openEditDrawer"
|
||||
@create-entry="openCreateDrawer"
|
||||
@move-entry="onMoveEntry"
|
||||
@@ -136,6 +139,8 @@ const drawerOpen = ref(false)
|
||||
const editingEntry = ref<TimeEntry | null>(null)
|
||||
const prefillStartedAt = ref<string | null>(null)
|
||||
const clipboard = ref<TimeEntry | null>(null)
|
||||
const pageHeaderEl = ref<HTMLElement | null>(null)
|
||||
const pageHeaderHeight = ref(0)
|
||||
|
||||
const contextMenu = reactive({
|
||||
visible: false,
|
||||
@@ -163,6 +168,12 @@ const typeOptions = computed(() =>
|
||||
types.value.map(t => ({ label: t.label, value: t.id }))
|
||||
)
|
||||
|
||||
let pageHeaderResizeObserver: ResizeObserver | null = null
|
||||
|
||||
function updatePageHeaderHeight() {
|
||||
pageHeaderHeight.value = pageHeaderEl.value?.offsetHeight ?? 0
|
||||
}
|
||||
|
||||
const filteredEntries = computed(() => {
|
||||
let result = entries.value
|
||||
if (selectedProjectId.value) {
|
||||
@@ -263,6 +274,24 @@ async function onPaste() {
|
||||
await loadEntries()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updatePageHeaderHeight()
|
||||
|
||||
if (!pageHeaderEl.value || typeof ResizeObserver === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
pageHeaderResizeObserver = new ResizeObserver(() => {
|
||||
updatePageHeaderHeight()
|
||||
})
|
||||
pageHeaderResizeObserver.observe(pageHeaderEl.value)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
pageHeaderResizeObserver?.disconnect()
|
||||
})
|
||||
|
||||
|
||||
async function onDelete(entry: TimeEntry) {
|
||||
await timeEntryService.remove(entry.id)
|
||||
await loadEntries()
|
||||
|
||||
Reference in New Issue
Block a user