feat: simplify today into plain list
This commit is contained in:
+10
-33
@@ -321,12 +321,8 @@ const activeName = computed(() => {
|
||||
if (activeView.value === 'settings') return '设置与数据'
|
||||
return lists.value.find((item) => item.id === activeList.value)?.name || '收集箱'
|
||||
})
|
||||
const todayHabitProgress = computed(() => `${todayHabitCompleted.value} / ${todayHabitTotal.value}`)
|
||||
const todayTaskRemaining = computed(() => Math.max(0, todayTaskTotal.value - todayTaskCompleted.value))
|
||||
const todayHabitRemaining = computed(() => Math.max(0, todayHabitTotal.value - todayHabitCompleted.value))
|
||||
const progressWidth = (completed: number, total: number) => `${total > 0 ? Math.min(100, Math.round(completed / total * 100)) : 0}%`
|
||||
const todayTaskProgressPercent = computed(() => progressWidth(todayTaskCompleted.value, todayTaskTotal.value))
|
||||
const todayHabitProgressPercent = computed(() => progressWidth(todayHabitCompleted.value, todayHabitTotal.value))
|
||||
function persistTodaySectionCollapse() {
|
||||
writeTodaySectionCollapse(window.localStorage, TODAY_SECTION_COLLAPSE_KEY, todaySectionCollapse.value)
|
||||
}
|
||||
@@ -334,17 +330,6 @@ function toggleTodaySection(section: keyof TodaySectionCollapse) {
|
||||
todaySectionCollapse.value[section] = !todaySectionCollapse.value[section]
|
||||
persistTodaySectionCollapse()
|
||||
}
|
||||
async function navigateTodaySection(section: 'tasks' | 'habits') {
|
||||
if (todaySectionCollapse.value[section]) {
|
||||
todaySectionCollapse.value[section] = false
|
||||
persistTodaySectionCollapse()
|
||||
}
|
||||
await nextTick()
|
||||
await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))
|
||||
const heading = document.getElementById(`today-${section}-heading`)
|
||||
heading?.focus({ preventScroll: true })
|
||||
document.getElementById(`today-${section}`)?.scrollIntoView({ behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth', block: 'start' })
|
||||
}
|
||||
function updateTodayHabitSummary(value: { total: number; completed: number }) {
|
||||
todayHabitTotal.value = value.total
|
||||
todayHabitCompleted.value = value.completed
|
||||
@@ -1519,12 +1504,12 @@ onUnmounted(() => {
|
||||
</AppSheet>
|
||||
</aside>
|
||||
|
||||
<main @touchstart="startSearchPull" @touchmove="moveSearchPull" @touchend="finishSearchPull" @touchcancel="cancelSearchPull">
|
||||
<main :class="{'today-main':activeView==='today'}" @touchstart="startSearchPull" @touchmove="moveSearchPull" @touchend="finishSearchPull" @touchcancel="cancelSearchPull">
|
||||
<header class="topbar" :inert="memoBackgroundInert ? true : undefined">
|
||||
<button class="icon" :aria-label="(sidebarCollapsed ? '展开' : '收起') + '菜单'" :aria-expanded="sidebarCollapsed ? 'false' : 'true'" @click="toggleSidebar"><Menu /></button>
|
||||
<div class="topbar-title"><h1 :title="activeName">{{ activeName }}</h1></div>
|
||||
<div v-if="activeView!=='today'" class="topbar-title"><h1 :title="activeName">{{ activeName }}</h1></div>
|
||||
<div v-if="['today', 'tasks', 'upcoming', 'habits'].includes(activeView)" class="topbar-actions">
|
||||
<CompletedFilterPill v-model="showCompleted" class="topbar-filter" />
|
||||
<CompletedFilterPill v-if="activeView!=='today'" v-model="showCompleted" class="topbar-filter" />
|
||||
<button class="icon topbar-refresh" :class="{spinning:refreshing}" type="button" aria-label="刷新当前页面" title="刷新" :disabled="refreshing || loading" @click="refreshCurrentView"><RefreshCw /></button>
|
||||
</div>
|
||||
<div v-if="taskSearchAvailable" class="search-reveal" :class="{'mobile-search-open':mobileSearchOpen,'mobile-search-pulling':searchPullDistance>0}" :style="searchRevealStyle">
|
||||
@@ -1539,30 +1524,22 @@ onUnmounted(() => {
|
||||
<MemoPanel v-else-if="activeView==='memos'" ref="memoPanel" :request="api" @scope="memoTrash=$event==='trash'" @detail="memoDetailOpen=$event" @notice="toast" />
|
||||
<CountdownPanel ref="countdownComposer" v-else-if="activeView==='countdowns'" @notice="toast" />
|
||||
<template v-else>
|
||||
<section v-if="activeView==='today'" class="today-board" aria-labelledby="today-board-title">
|
||||
<h2 id="today-board-title" class="sr-only">今日纸笺</h2>
|
||||
<section v-if="activeView==='today'" class="today-context" aria-label="今日概览">
|
||||
<TodayEnvironmentStrip :environment="todayEnvironment" :loading="todayEnvironmentLoading" :failed="todayEnvironmentError" />
|
||||
<div class="today-board__progress" aria-label="今日任务与习惯进度">
|
||||
<button class="today-track today-task-track" type="button" aria-controls="today-tasks" @click="navigateTodaySection('tasks')">
|
||||
<span class="today-track-head"><strong>任务 {{ todayTaskCompleted }} / {{ todayTaskTotal }}</strong><span>还有 {{ todayTaskRemaining }} 项</span></span>
|
||||
<span class="today-track-rail" role="progressbar" aria-label="今日任务进度" aria-valuemin="0" :aria-valuemax="todayTaskTotal" :aria-valuenow="todayTaskCompleted"><i class="today-track-fill" :style="{ width: todayTaskProgressPercent }" /></span>
|
||||
</button>
|
||||
<button class="today-track today-habit-track" type="button" aria-controls="today-habits" @click="navigateTodaySection('habits')">
|
||||
<span class="today-track-head"><strong>习惯 {{ todayHabitProgress }}</strong><span>还有 {{ todayHabitRemaining }} 项</span></span>
|
||||
<span class="today-track-rail" role="progressbar" aria-label="今日习惯进度" aria-valuemin="0" :aria-valuemax="todayHabitTotal" :aria-valuenow="todayHabitCompleted"><i class="today-track-fill" :style="{ width: todayHabitProgressPercent }" /></span>
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="today-page-title">今天</h1>
|
||||
<p class="today-remaining">还有 {{ todayTaskRemaining + todayHabitRemaining }} 项待完成</p>
|
||||
<CompletedFilterPill v-model="showCompleted" class="today-inline-filter" />
|
||||
</section>
|
||||
<template v-if="activeView==='today'">
|
||||
<section v-if="overdueTaskTree.length" class="overdue-section today-collapsible-section">
|
||||
<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>
|
||||
<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">逾期</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 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>
|
||||
<button id="today-tasks-heading" class="today-section-toggle today-section-anchor" type="button" :aria-expanded="!todaySectionCollapse.tasks" aria-controls="today-tasks" @click="toggleTodaySection('tasks')"><span class="today-section-title"><ListTodo/>任务</span><span class="today-section-summary">{{totalTasks}} 项</span><ChevronRight v-if="todaySectionCollapse.tasks" aria-hidden="true"/><ChevronDown v-else aria-hidden="true"/></button>
|
||||
<button id="today-tasks-heading" class="today-section-toggle today-section-anchor" type="button" :aria-expanded="!todaySectionCollapse.tasks" aria-controls="today-tasks" @click="toggleTodaySection('tasks')"><span class="today-section-title">今天</span><span class="today-section-summary">{{totalTasks}} 项</span><ChevronRight v-if="todaySectionCollapse.tasks" aria-hidden="true"/><ChevronDown v-else aria-hidden="true"/></button>
|
||||
</template>
|
||||
<div v-if="activeView!=='today'" class="list-toolbar"><span v-if="activeView==='trash' || totalPages > 1 || totalTasks > 0">{{ totalPages > 1 ? `第 ${page} / ${totalPages} 页 · ` : '' }}共 {{totalTasks}} 项</span><span class="list-toolbar-actions"><button v-if="query" class="link" @click="query=''">清除搜索</button><button v-if="taskReorderAvailable" class="soft-button reorder-mode-toggle task-reorder-toggle" type="button" :aria-pressed="taskReorderMode" @click="taskReorderMode=!taskReorderMode;cancelTaskReorder()">{{ taskReorderMode ? '完成' : '调整顺序' }}</button></span></div>
|
||||
<div v-if="activeView!=='trash' && totalPages > 1" class="pager"><button class="secondary" :disabled="page<=1 || loading" @click="previousPage">上一页</button><span>{{page}} / {{totalPages}}</span><button class="secondary" :disabled="page>=totalPages || loading" @click="nextPage">下一页</button></div>
|
||||
@@ -1579,7 +1556,7 @@ onUnmounted(() => {
|
||||
<div v-else-if="!visibleTasks.length&&!loading" class="empty"><ListTodo/><b>{{ query ? '没有匹配的任务' : hiddenCompletedTaskCount > 0 ? '已完成任务已隐藏' : '这里还很安静' }}</b><span>{{query?'换个关键词试试':hiddenCompletedTaskCount > 0 ? '开启“显示已完成”即可查看。':'写下第一件想完成的小事吧'}}</span><button v-if="activeView==='today' && !query && hiddenCompletedTaskCount === 0" class="soft-button empty-action" @click="openTaskCompose"><Plus/>添加今天任务</button></div>
|
||||
</section>
|
||||
<div v-if="activeView==='today'" class="today-habits-section today-section-anchor">
|
||||
<button id="today-habits-heading" class="today-section-toggle" type="button" :aria-expanded="!todaySectionCollapse.habits" aria-controls="today-habits" @click="toggleTodaySection('habits')"><span class="today-section-title"><Repeat2/>习惯</span><span class="today-section-summary">{{todayHabitCompleted}} / {{todayHabitTotal}}</span><ChevronRight v-if="todaySectionCollapse.habits" aria-hidden="true"/><ChevronDown v-else aria-hidden="true"/></button>
|
||||
<button id="today-habits-heading" class="today-section-toggle" type="button" :aria-expanded="!todaySectionCollapse.habits" aria-controls="today-habits" @click="toggleTodaySection('habits')"><span class="today-section-title">习惯</span><span class="today-section-summary">{{todayHabitCompleted}} / {{todayHabitTotal}}</span><ChevronRight v-if="todaySectionCollapse.habits" aria-hidden="true"/><ChevronDown v-else aria-hidden="true"/></button>
|
||||
<div v-show="!todaySectionCollapse.habits" id="today-habits" role="region" aria-labelledby="today-habits-heading">
|
||||
<MvpPanel ref="habitComposer" view="today-habits" :show-completed="showCompleted" @changed="refreshAll" @notice="toast" @summary="updateTodayHabitSummary" />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user