diff --git a/frontend/e2e/visual-regression.spec.ts-snapshots/inbox-mobile-390.png b/frontend/e2e/visual-regression.spec.ts-snapshots/inbox-mobile-390.png index 5fc7310..8c6a4de 100644 Binary files a/frontend/e2e/visual-regression.spec.ts-snapshots/inbox-mobile-390.png and b/frontend/e2e/visual-regression.spec.ts-snapshots/inbox-mobile-390.png differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 0b7dbe2..c82d829 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -111,6 +111,7 @@ const markdownPreview = ref(false) const taskNoteEditor = ref(null) const SHOW_COMPLETED_STORAGE_KEY = 'dodo.show-completed' const showCompleted = ref(readStoredBoolean(window.localStorage, SHOW_COMPLETED_STORAGE_KEY, true)) +const completedFilterReveal = ref(false) const TODAY_SECTION_COLLAPSE_KEY = 'dodo.today-section-collapse.v1' const todaySectionCollapse = ref(readTodaySectionCollapse(window.localStorage, TODAY_SECTION_COLLAPSE_KEY)) const page = ref(1) @@ -449,6 +450,10 @@ watch(taskReorderAvailable, () => { }) watch(showCompleted, (value) => { writeStoredBoolean(window.localStorage, SHOW_COMPLETED_STORAGE_KEY, value) + if (value) { + completedFilterReveal.value = true + window.setTimeout(() => { completedFilterReveal.value = false }, 500) + } if (isTaskView(activeView.value)) { page.value = 1; loadAll() } }) @@ -1819,15 +1824,15 @@ onUnmounted(() => {

回收站

删除的任务保留在这里,可整组恢复或永久删除。

@@ -1846,9 +1851,10 @@ onUnmounted(() => {
-
+
+
已隐藏已完成任务
{{ activeView==='trash' ? '回收站是空的' : hiddenCompletedTaskCount > 0 ? '已完成任务已隐藏' : '这里还很安静' }}{{activeView==='trash' ? '删除的任务会显示在这里' : hiddenCompletedTaskCount > 0 ? '开启“显示已完成”即可查看。':'写下第一件想完成的小事吧'}}
+
- -
+ +
diff --git a/frontend/src/TodaySections.test.ts b/frontend/src/TodaySections.test.ts index 65a0c97..03b09a0 100644 --- a/frontend/src/TodaySections.test.ts +++ b/frontend/src/TodaySections.test.ts @@ -36,14 +36,14 @@ describe('Today independent collapsible sections', () => { expect(app.match(/class="today-section-toggle(?: today-section-anchor)?"/g)).toHaveLength(3) expect(app).toContain('{{totalTasks}}') expect(app).not.toContain('{{taskTree.length}} 项') - expect(app).toContain("{{ todaySectionCollapse.overdue ? '›' : '⌄' }}") + expect(app).toContain('') expect(app).not.toContain(' { - expect(app).toContain('
') - expect(app).toContain('
') + expect(app).toContain('
', app.indexOf('i,.calendar-event-detail dd i,.calendar-source-copy i{width:9px;height:9px;display:inline-block;flex:0 0 auto;border-radius:50%}.calendar-agenda{display:grid;gap:20px}.calendar-agenda section{display:grid}.calendar-agenda h2{min-height:40px;margin:0;display:flex;align-items:center;border-bottom:1px solid #e8e0d5;font-size:13px}.calendar-event-row{min-height:62px;display:grid;grid-template-columns:10px 54px minmax(0,1fr) 24px;align-items:center;gap:10px;padding:0 4px;border:0;border-bottom:1px solid #e8e0d5;background:transparent;text-align:left}.calendar-event-row:hover{background:#fff8ee}.calendar-event-row time{color:var(--muted);font-size:12px}.calendar-event-row span{min-width:0;display:grid;gap:4px}.calendar-event-row b,.calendar-event-row small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.calendar-event-row b{font-size:14px;font-weight:620}.calendar-event-row small{color:var(--muted);font-size:11px}.calendar-event-row>svg{color:#aa9f92}.calendar-empty{min-height:260px;display:grid;place-items:center;align-content:center;gap:9px;color:var(--muted);text-align:center}.calendar-empty svg{width:32px;height:32px}.calendar-empty b{color:var(--text-primary)}.calendar-event-detail,.calendar-sources-sheet{width:min(520px,100%);max-height:min(88dvh,760px)}.calendar-event-detail .app-sheet__header{padding:24px 24px 18px;align-items:flex-start;border-bottom:0}.calendar-event-detail .app-sheet__header h3{max-width:calc(100% - 48px);font-size:22px;font-weight:720;line-height:1.38;letter-spacing:-.02em}.calendar-event-detail .app-sheet__body{padding:0 24px 32px}.calendar-event-detail__meta{display:flex;flex-wrap:wrap;gap:8px 14px;padding:0 0 20px;border-bottom:1px solid #e8e0d5;color:var(--muted);font-size:12px;line-height:1.45}.calendar-event-detail__meta span{display:inline-flex;align-items:center;gap:7px;min-width:0}.calendar-event-detail__meta i{width:8px;height:8px;display:inline-block;flex:0 0 auto;border-radius:50%}.calendar-event-detail__content{padding-top:22px}.calendar-event-detail__content p{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text);font-size:14px;line-height:1.9}.calendar-event-detail__empty{margin:0;padding-top:22px;color:var(--muted);font-size:13px}.calendar-source-add{justify-self:start}.calendar-source-list{display:grid}.calendar-source-list article{min-height:72px;display:grid;grid-template-columns:minmax(0,1fr) auto 44px 44px 44px;align-items:center;gap:4px;border-bottom:1px solid #e8e0d5}.calendar-source-copy{min-width:0;display:grid;gap:3px}.calendar-source-copy b{display:flex;align-items:center;gap:7px;font-size:13px}.calendar-source-copy small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:10px}.calendar-source-copy .calendar-source-error{color:var(--danger);white-space:normal}.calendar-source-list article>button{width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;border-radius:9px}.calendar-source-toggle{min-height:44px;display:flex;align-items:center;gap:5px;font-size:11px}.calendar-subscription-form{width:min(460px,100%)}.calendar-subscription-form .app-sheet__body label{display:grid;gap:6px;color:#756d61;font-size:12px;font-weight:650}.calendar-subscription-form input{min-height:44px;width:100%;padding:8px 11px;border:1px solid var(--border-cream)}.calendar-subscription-form input[type=color]{padding:5px;width:72px}.calendar-subscription-form .calendar-form-toggle{display:flex;align-items:center;min-height:44px}.calendar-subscription-form .calendar-form-toggle input{width:18px;min-height:18px}.calendar-view.loading{opacity:.72}@media(max-width:930px){.calendar-view{width:min(100%,630px)}.calendar-event-detail,.calendar-sources-sheet,.calendar-subscription-form{width:100%;max-width:100%;border-radius:20px 20px 0 0!important}}@media(max-width:720px){.calendar-view{width:100%;gap:13px}.calendar-heading .calendar-manage{font-size:0;padding:0;width:44px}.calendar-heading .calendar-manage svg{width:19px;height:19px}.calendar-toolbar{grid-template-columns:44px 54px minmax(0,1fr) 44px}.calendar-toolbar .calendar-today{width:54px}.calendar-week-strip{gap:3px;padding:7px}.calendar-week-day{min-height:64px}.calendar-week-day i{right:4px;top:4px;min-width:16px;height:16px}.calendar-source-list article{grid-template-columns:minmax(0,1fr) 44px 44px 44px}.calendar-source-toggle{grid-column:1/-1;grid-row:2}.calendar-event-row{grid-template-columns:9px 48px minmax(0,1fr) 20px}.calendar-filters{width:100%;margin-inline:-4px;padding-inline:4px}}@media(max-width:390px){.calendar-week-strip{display:flex;overflow-x:auto;scroll-snap-type:x proximity}.calendar-week-day{flex:0 0 44px;scroll-snap-align:start}.calendar-event-row{gap:7px}.calendar-source-list article{gap:1px}}@media(min-width:931px){.calendar-view{padding-top:4px}.calendar-event-detail{grid-column:3;grid-row:1;width:var(--detail-width,350px);height:100vh;max-height:none;padding:0;border-radius:0;border-top:0;border-right:0;border-bottom:0;box-shadow:inset 1px 0 0 #fff;overflow:hidden;display:flex;flex-direction:column}.calendar-event-detail .app-sheet__body{flex:1 1 auto;overflow-y:auto}.calendar-sources-sheet{border-radius:var(--radius-panel)}}@media(min-width:1440px){.calendar-view{width:min(100%,1040px)}} +.calendar-view{min-width:0;width:min(100%,900px);margin:0 auto;padding-bottom:42px;display:grid;gap:16px}.calendar-heading{display:flex;align-items:center;justify-content:space-between;gap:16px}.calendar-heading p{margin:0;color:var(--text-secondary);font-size:13px}.calendar-manage{min-height:44px}.calendar-toolbar{min-height:48px;display:grid;grid-template-columns:44px 64px minmax(0,1fr) 44px;align-items:center;border-block:1px solid var(--border-hairline)}.calendar-toolbar button{width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;border-radius:var(--radius-control)}.calendar-toolbar .calendar-today{width:64px}.calendar-toolbar strong{text-align:center;font-size:16px}.calendar-week-strip{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:8px;padding:10px;border:1px solid var(--border-cream);border-radius:var(--radius-list);background:var(--surface-raised);box-shadow:inset 0 1px rgba(255,255,255,.9)}.calendar-week-day{position:relative;min-width:0;min-height:76px;display:grid;place-items:center;align-content:center;gap:4px;border:0;border-radius:var(--radius-control);background:transparent}.calendar-week-day small{color:var(--text-secondary);font-size:11px}.calendar-week-day b{font-size:18px}.calendar-week-day i{position:absolute;right:7px;top:7px;min-width:18px;height:18px;display:grid;place-items:center;border-radius:999px;background:var(--calendar-week-day-bg);color:var(--calendar-week-day-ink);font-size:11px;font-style:normal}.calendar-week-day.is-selected{background:var(--accent);color:var(--white);box-shadow:0 8px 18px rgba(241,90,41,.22)}.calendar-week-day.is-selected small{color:var(--white)}.calendar-week-day.is-selected i{background:var(--calendar-week-day-bg-2);color:var(--accent)}.calendar-week-day.is-today:not(.is-selected){box-shadow:inset 0 0 0 1px var(--calendar-week-day-shadow)}.calendar-filters{min-width:0;max-width:100%;display:flex;gap:8px;overflow-x:auto;overflow-y:hidden;contain:layout paint;padding-bottom:2px;overscroll-behavior-inline:contain}.calendar-filters label{min-height:44px;display:flex;align-items:center;gap:7px;padding:0 12px;border:1px solid var(--border-cream);border-radius:999px;background:var(--surface-raised);font-size:12px;white-space:nowrap}.calendar-filters input{position:absolute;opacity:0;pointer-events:none}.calendar-filters label:has(input:not(:checked)){opacity:.48}.calendar-filters i,.calendar-event-row>i,.calendar-event-detail dd i,.calendar-source-copy i{width:9px;height:9px;display:inline-block;flex:0 0 auto;border-radius:50%}.calendar-agenda{display:grid;gap:20px}.calendar-agenda section{display:grid}.calendar-agenda h2{min-height:40px;margin:0;display:flex;align-items:center;border-bottom:1px solid var(--border-hairline);font-size:13px}.calendar-event-row{min-height:62px;display:grid;grid-template-columns:10px 54px minmax(0,1fr) 24px;align-items:center;gap:10px;padding:0 4px;border:0;border-bottom:1px solid var(--border-hairline);background:transparent;text-align:left}.calendar-event-row:hover{background:var(--event-hover)}.calendar-event-row time{color:var(--text-secondary);font-size:12px}.calendar-event-row span{min-width:0;display:grid;gap:4px}.calendar-event-row b,.calendar-event-row small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.calendar-event-row b{font-size:14px;font-weight:600}.calendar-event-row small{color:var(--text-secondary);font-size:11px}.calendar-event-row>svg{color:var(--calendar-event-row-ink)}.calendar-empty{min-height:260px;display:grid;place-items:center;align-content:center;gap:9px;color:var(--text-secondary);text-align:center}.calendar-empty svg{width:32px;height:32px}.calendar-empty b{color:var(--text-primary)}.calendar-event-detail,.calendar-sources-sheet{width:min(520px,100%);max-height:min(88dvh,760px)}.calendar-event-detail .app-sheet__header{padding:24px 24px 18px;align-items:flex-start;border-bottom:0}.calendar-event-detail .app-sheet__header h3{max-width:calc(100% - 48px);font-size:22px;font-weight:700;line-height:1.38;letter-spacing:-.02em}.calendar-event-detail .app-sheet__body{padding:0 24px 32px}.calendar-event-detail__meta{display:flex;flex-wrap:wrap;gap:8px 14px;padding:0 0 20px;border-bottom:1px solid var(--border-hairline);color:var(--text-secondary);font-size:12px;line-height:1.45}.calendar-event-detail__meta span{display:inline-flex;align-items:center;gap:7px;min-width:0}.calendar-event-detail__meta i{width:8px;height:8px;display:inline-block;flex:0 0 auto;border-radius:50%}.calendar-event-detail__content{padding-top:22px}.calendar-event-detail__content p{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text-primary);font-size:14px;line-height:1.9}.calendar-event-detail__empty{margin:0;padding-top:22px;color:var(--text-secondary);font-size:13px}.calendar-source-add{justify-self:start}.calendar-source-list{display:grid}.calendar-source-list article{min-height:72px;display:grid;grid-template-columns:minmax(0,1fr) auto 44px 44px 44px;align-items:center;gap:4px;border-bottom:1px solid var(--border-hairline)}.calendar-source-copy{min-width:0;display:grid;gap:3px}.calendar-source-copy b{display:flex;align-items:center;gap:7px;font-size:13px}.calendar-source-copy small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-secondary);font-size:11px}.calendar-source-copy .calendar-source-error{color:var(--danger);white-space:normal}.calendar-source-list article>button{width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;border-radius:var(--radius-control)}.calendar-source-toggle{min-height:44px;display:flex;align-items:center;gap:5px;font-size:11px}.calendar-subscription-form{width:min(460px,100%)}.calendar-subscription-form .app-sheet__body label{display:grid;gap:6px;color:var(--text-secondary);font-size:12px;font-weight:600}.calendar-subscription-form input{min-height:44px;width:100%;padding:8px 11px;border:1px solid var(--border-cream)}.calendar-subscription-form input[type=color]{padding:5px;width:72px}.calendar-subscription-form .calendar-form-toggle{display:flex;align-items:center;min-height:44px}.calendar-subscription-form .calendar-form-toggle input{width:18px;min-height:18px}.calendar-view.loading{opacity:.72}@media(max-width:930px){.calendar-view{width:min(100%,630px)}.calendar-event-detail,.calendar-sources-sheet,.calendar-subscription-form{width:100%;max-width:100%;border-radius:var(--radius-panel) var(--radius-panel) 0 0!important}}@media(max-width:720px){.calendar-view{width:100%;gap:13px}.calendar-heading .calendar-manage{font-size:0;padding:0;width:44px}.calendar-heading .calendar-manage svg{width:19px;height:19px}.calendar-toolbar{grid-template-columns:44px 54px minmax(0,1fr) 44px}.calendar-toolbar .calendar-today{width:54px}.calendar-week-strip{gap:3px;padding:7px}.calendar-week-day{min-height:64px}.calendar-week-day i{right:4px;top:4px;min-width:16px;height:16px}.calendar-source-list article{grid-template-columns:minmax(0,1fr) 44px 44px 44px}.calendar-source-toggle{grid-column:1/-1;grid-row:2}.calendar-event-row{grid-template-columns:9px 48px minmax(0,1fr) 20px}.calendar-filters{width:100%;margin-inline:-4px;padding-inline:4px}}@media(max-width:390px){.calendar-week-strip{display:flex;overflow-x:auto;scroll-snap-type:x proximity}.calendar-week-day{flex:0 0 44px;scroll-snap-align:start}.calendar-event-row{gap:7px}.calendar-source-list article{gap:1px}}@media(min-width:931px){.calendar-view{padding-top:4px}.calendar-event-detail{grid-column:3;grid-row:1;width:var(--detail-width,350px);height:100vh;max-height:none;padding:0;border-radius:0;border-top:0;border-right:0;border-bottom:0;box-shadow:inset 1px 0 0 var(--white);overflow:hidden;display:flex;flex-direction:column}.calendar-event-detail .app-sheet__body{flex:1 1 auto;overflow-y:auto}.calendar-sources-sheet{border-radius:var(--radius-panel)}}@media(min-width:1440px){.calendar-view{width:min(100%,1040px)}} + + +/* Restrained motion: picker open (scale 140ms desktop / rise 180ms mobile) and month shift crossfade. */ +.calendar-picker-enter-active,.calendar-picker-leave-active{transition:opacity 140ms cubic-bezier(.2,.8,.3,1)} +.calendar-picker-enter-from,.calendar-picker-leave-to{opacity:0} +.calendar-picker-enter-active .calendar-picker{transition:transform 140ms cubic-bezier(.2,.8,.3,1),opacity 140ms cubic-bezier(.2,.8,.3,1)} +.calendar-picker-enter-from .calendar-picker{transform:scale(.98);opacity:0} +.calendar-picker-leave-active .calendar-picker{transition:opacity 160ms cubic-bezier(.2,.8,.3,1)} +@media(max-width:600px){ +.calendar-picker-enter-active .calendar-picker{transition:transform 180ms ease-out,opacity 180ms ease-out} +.calendar-picker-enter-from .calendar-picker{transform:translateY(16px);opacity:0} +} +.calendar-picker__grid.shift-next{animation:calendar-month-next 140ms ease-out} +.calendar-picker__grid.shift-prev{animation:calendar-month-prev 140ms ease-out} +@keyframes calendar-month-next{from{opacity:0;transform:translateX(8px)}to{opacity:1;transform:none}} +@keyframes calendar-month-prev{from{opacity:0;transform:translateX(-8px)}to{opacity:1;transform:none}} diff --git a/frontend/src/components/AppSheet.vue b/frontend/src/components/AppSheet.vue index 9bc7d95..9eeb157 100644 --- a/frontend/src/components/AppSheet.vue +++ b/frontend/src/components/AppSheet.vue @@ -74,11 +74,13 @@ onBeforeUnmount(deactivate)