refactor: focus habit completion feedback
ci / gitleaks (push) Successful in 7s
ci / docker (push) Successful in 4m18s

This commit is contained in:
2026-09-08 20:05:42 +08:00
parent 144abd529b
commit 89374f2db9
3 changed files with 43 additions and 11 deletions
+17 -2
View File
@@ -188,6 +188,17 @@ function habitProgressMax(h: Habit) {
function habitProgressValue(h: Habit) {
return Math.min(Math.max(Number(logFor(h, todayKey.value)?.value ?? 0), 0), habitProgressMax(h))
}
function habitWeekday(day: string) {
const [year, month, date] = day.split('-').map(Number)
return new Intl.DateTimeFormat('zh-CN', { weekday: 'narrow' }).format(new Date(year, month - 1, date))
}
function habitCellDone(h: Habit, cell: NonNullable<Habit['cells']>[number]) {
return isHabitComplete(h.kind, cell.value, h.target ?? 1)
}
function habitCellLabel(h: Habit, cell: NonNullable<Habit['cells']>[number]) {
const state = !cell.scheduled ? '未安排' : cell.paused ? '已暂停' : habitCellDone(h, cell) ? '已完成' : '未完成'
return `${cell.day} ${habitWeekday(cell.day)}${state}`
}
function setLocalHabitValue(h: Habit, next: number | boolean) {
habits.value = habits.value.map((item) => item.id !== h.id
@@ -424,8 +435,7 @@ onBeforeUnmount(() => {
<!-- 今日习惯只展示今天该做的习惯复用正式习惯行样式 -->
<div v-if="view === 'today-habits' && (habits.length || !busy)" class="habit-list today-habit-list">
<div class="habit-toolbar habit-toolbar-today"><label><input v-model="hideCompletedHabits" type="checkbox"> 隐藏已完成</label></div>
<article v-for="h in visibleTodayHabits" :key="h.id" :data-habit-id="h.id" class="habit-row swipeable" :class="{ done: isDone(h, todayKey), ready: Math.abs(habitSwipeOffsets[h.id] ?? 0) >= 64, reordering: habitReorder?.id === h.id, 'reorder-target': habitReorderTarget === h.id }" :style="{ '--swipe-x': `${habitSwipeOffsets[h.id] ?? 0}px`, '--reorder-y': `${habitReorder?.id === h.id ? habitReorder.offsetY : 0}px` }" @pointerdown="startHabitPointer(h, $event)" @pointermove="moveHabitPointer(h, $event)" @pointerup="finishHabitPointer(h, $event)" @pointercancel="cancelHabitPointer(h)" @touchstart.passive="startHabitSwipe(h, $event)" @touchmove.passive="moveHabitSwipe(h, $event)" @touchend="finishHabitSwipe(h, $event)" @touchcancel="cancelHabitSwipe(h)">
<button class="drag-handle habit-drag-handle" :disabled="hideCompletedHabits" aria-label="上下拖动习惯排序" title="上下拖动排序" @pointerdown.stop="startHabitReorder(h, $event)" @pointermove.stop="moveHabitReorder(h, $event)" @pointerup.stop="finishHabitReorder(h, $event)" @pointercancel.stop="cancelHabitReorder"><GripVertical/></button>
<article v-for="h in visibleTodayHabits" :key="h.id" :data-habit-id="h.id" class="habit-row today-habit-row swipeable" :class="{ done: isDone(h, todayKey), ready: Math.abs(habitSwipeOffsets[h.id] ?? 0) >= 64 }" :style="{ '--swipe-x': `${habitSwipeOffsets[h.id] ?? 0}px` }" @pointerdown="startHabitPointer(h, $event)" @pointermove="moveHabitPointer(h, $event)" @pointerup="finishHabitPointer(h, $event)" @pointercancel="cancelHabitPointer(h)" @touchstart.passive="startHabitSwipe(h, $event)" @touchmove.passive="moveHabitSwipe(h, $event)" @touchend="finishHabitSwipe(h, $event)" @touchcancel="cancelHabitSwipe(h)">
<button class="task-check habit-check" :aria-label="isDone(h, todayKey) ? `减少${h.name}一次` : `完成${h.name}一次`" :aria-pressed="isDone(h, todayKey)" @click.stop="toggleHabitFromButton(h)"><span class="task-check-mark"><Check v-if="isDone(h, todayKey)" /></span></button>
<div class="habit-main">
<span class="habit-name">{{ h.name }}</span>
@@ -458,6 +468,11 @@ onBeforeUnmount(() => {
<span class="habit-name">{{ h.name }}</span>
<small v-if="habitProgressText(h)" class="habit-progress">{{ habitProgressText(h) }}</small>
<progress v-if="h.kind === 'numeric'" class="habit-progress-bar" :value="habitProgressValue(h)" :max="habitProgressMax(h)" :aria-label="`${h.name}进度:${habitProgressText(h)}`"></progress>
<div class="habit-week" aria-label="最近一周打卡">
<span v-for="cell in h.cells" :key="cell.day" class="habit-week-cell" :class="{ done: habitCellDone(h, cell), unscheduled: !cell.scheduled || cell.paused, today: cell.day === todayKey }" :title="habitCellLabel(h, cell)" :aria-label="habitCellLabel(h, cell)">
<small class="habit-week-day">{{ habitWeekday(cell.day) }}</small><i></i>
</span>
</div>
</div>
</article>
<div v-if="!habits.length && !busy" class="empty-panel">还没有习惯从一件容易坚持的小事开始</div>