fix: align overdue task swipe motion
This commit is contained in:
@@ -1498,7 +1498,7 @@ onUnmounted(() => {
|
||||
<button id="today-overdue-heading" class="today-section-toggle" type="button" :aria-expanded="!todaySectionCollapse.overdue" aria-controls="today-overdue" @click="toggleTodaySection('overdue')"><span class="today-section-title"><CalendarDays/>已过期</span><span class="today-section-summary">{{overdueTaskTree.length}} 项</span><ChevronRight v-if="todaySectionCollapse.overdue" aria-hidden="true"/><ChevronDown v-else aria-hidden="true"/></button>
|
||||
<div v-show="!todaySectionCollapse.overdue" id="today-overdue" class="task-list overdue-list" role="region" aria-labelledby="today-overdue-heading">
|
||||
<template v-for="node in overdueTaskTree" :key="`overdue-${node.task.id}`">
|
||||
<article :data-task-id="node.task.id" class="task-row overdue-task" :class="{'completion-exiting':completionExitingTaskIds.has(node.task.id)}"><button class="task-check" :aria-label="`完成${node.task.title}`" :aria-pressed="false" @click.stop="toggle(node.task)"><span class="task-check-mark" :class="`p${node.task.priority}`"></span></button><div class="task-main" role="button" tabindex="0" @click="selectTask(node.task)" @keydown.enter="selectTask(node.task)"><strong :title="node.task.title">{{node.task.title}}</strong><span v-if="node.subtasks.length" class="meta"><span class="meta-item"><ListChecks/>{{node.subtasks.filter(t=>t.completed).length}}/{{node.subtasks.length}}</span></span></div><span v-if="node.task.due_at" class="task-tail"><TaskDueDisplay :due-at="node.task.due_at" :due-has-time="node.task.due_has_time" :completed="node.task.completed" :now-ms="taskDueNowMs" /></span></article>
|
||||
<article :data-task-id="node.task.id" class="task-row overdue-task swipeable" :class="{'just-completed':justCompletedTaskIds.has(node.task.id),'completion-exiting':completionExitingTaskIds.has(node.task.id),ready:Math.abs(taskSwipeOffsets[node.task.id] ?? 0) >= 64}" :style="{ '--swipe-x': `${taskSwipeOffsets[node.task.id] ?? 0}px` }" @pointerdown="startTaskPointer(node.task, $event)" @pointermove="moveTaskPointer(node.task, $event)" @pointerup="finishTaskPointer(node.task, $event)" @pointercancel="cancelTaskPointer(node.task)" @touchstart.passive="startTaskSwipe(node.task, $event)" @touchmove.passive="moveTaskSwipe(node.task, $event)" @touchend="finishTaskSwipe(node.task, $event)" @touchcancel="cancelTaskSwipe(node.task)"><button class="task-check" :aria-label="`完成${node.task.title}`" :aria-pressed="false" @click.stop="toggle(node.task)"><span class="task-check-mark" :class="`p${node.task.priority}`"></span></button><div class="task-main" role="button" tabindex="0" @click="selectTaskUnlessSwiped(node.task)" @keydown.enter="selectTaskUnlessSwiped(node.task)" @keydown.space.prevent="selectTaskUnlessSwiped(node.task)"><strong :title="node.task.title">{{node.task.title}}</strong><span v-if="node.subtasks.length" class="meta"><span class="meta-item"><ListChecks/>{{node.subtasks.filter(t=>t.completed).length}}/{{node.subtasks.length}}</span></span></div><span v-if="node.task.due_at" class="task-tail"><TaskDueDisplay :due-at="node.task.due_at" :due-has-time="node.task.due_has_time" :completed="node.task.completed" :now-ms="taskDueNowMs" /></span></article>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -256,6 +256,18 @@ describe('completion feedback motion', () => {
|
||||
expect(css).toContain('@keyframes completion-slide-out')
|
||||
})
|
||||
|
||||
it('gives overdue tasks the same right-swipe completion motion as regular tasks and habits', () => {
|
||||
const overdueBlock = app.slice(app.indexOf('<section v-if="overdueTaskTree.length"'), app.indexOf('<button id="today-tasks-heading"'))
|
||||
expect(overdueBlock).toContain('class="task-row overdue-task swipeable"')
|
||||
expect(overdueBlock).toContain("'just-completed':justCompletedTaskIds.has(node.task.id)")
|
||||
expect(overdueBlock).toContain("ready:Math.abs(taskSwipeOffsets[node.task.id] ?? 0) >= 64")
|
||||
expect(overdueBlock).toContain("'--swipe-x': `${taskSwipeOffsets[node.task.id] ?? 0}px`")
|
||||
expect(overdueBlock).toContain('@pointerdown="startTaskPointer(node.task, $event)"')
|
||||
expect(overdueBlock).toContain('@touchstart.passive="startTaskSwipe(node.task, $event)"')
|
||||
expect(overdueBlock).toContain('@click="selectTaskUnlessSwiped(node.task)"')
|
||||
expect(overdueBlock).toContain('@keydown.space.prevent="selectTaskUnlessSwiped(node.task)"')
|
||||
})
|
||||
|
||||
it('animates only transient just-completed rows and respects reduced motion', () => {
|
||||
expect(css).toContain('.task-row.just-completed,.habit-row.just-completed{animation:completion-row-settle .34s cubic-bezier(.2,.85,.3,1)}')
|
||||
expect(css).toContain('.task-row.just-completed .task-check-mark,.habit-row.just-completed .task-check-mark{animation:completion-check-pop .38s cubic-bezier(.2,1.4,.35,1)}')
|
||||
@@ -561,11 +573,11 @@ describe('task and habit row decoration', () => {
|
||||
expect(purgeBlock).toContain("await mutateTrashTask(task, () => api(`/trash/${task.id}`")
|
||||
})
|
||||
|
||||
it('supports pointer dragging for desktop visible task completion', () => {
|
||||
expect(app.match(/@pointerdown="startTaskPointer/g)?.length).toBe(1)
|
||||
expect(app.match(/@pointermove="moveTaskPointer/g)?.length).toBe(1)
|
||||
expect(app.match(/@pointerup="finishTaskPointer/g)?.length).toBe(1)
|
||||
expect(app.match(/@pointercancel="cancelTaskPointer/g)?.length).toBe(1)
|
||||
it('supports pointer dragging for desktop task completion in regular and overdue rows', () => {
|
||||
expect(app.match(/@pointerdown="startTaskPointer/g)?.length).toBe(2)
|
||||
expect(app.match(/@pointermove="moveTaskPointer/g)?.length).toBe(2)
|
||||
expect(app.match(/@pointerup="finishTaskPointer/g)?.length).toBe(2)
|
||||
expect(app.match(/@pointercancel="cancelTaskPointer/g)?.length).toBe(2)
|
||||
})
|
||||
|
||||
it('supports pointer dragging for desktop habit rows in Today and Habits views', () => {
|
||||
|
||||
Reference in New Issue
Block a user