refactor: remove manual refresh and search controls
ci / gitleaks (push) Successful in 8s
ci / docker (push) Successful in 7m17s

This commit is contained in:
2026-09-19 21:15:23 +08:00
parent 0cf1c49094
commit 4973d56a64
29 changed files with 244 additions and 860 deletions
+33 -39
View File
@@ -160,7 +160,8 @@ describe('approved Settings 01 paper ledger', () => {
expect(app).not.toContain("'settings-main':activeView==='settings'")
expect(app).toContain(":class=\"{'settings-topbar':activeView==='settings'}\"")
expect(app).toContain("v-if=\"!['today','tasks','upcoming','habits','settings'].includes(activeView)\" class=\"topbar-title\"")
expect(app).toContain('v-if="activeView===\'settings\'" class="icon topbar-refresh settings-refresh"')
expect(app).not.toContain('v-if="activeView===\'settings\'" class="icon topbar-refresh settings-refresh"')
expect(app).not.toContain('aria-label="刷新当前页面"')
expect(mvpPanel).toContain('<header class="settings-heading"><h1>设置</h1><p>管理数据、账户与登录设备</p></header>')
expect(mvpPanel).toContain('<h2>数据与恢复</h2><small>完整备份</small>')
expect(mvpPanel).toContain("<h2>登录设备</h2><small>{{ sessionsState === 'success' ? `${sessions.length} 台` : '状态' }}</small>")
@@ -175,7 +176,7 @@ describe('approved Settings 01 paper ledger', () => {
expect(css).toContain('.settings-group>header{height:44px;padding:0;display:flex;align-items:center;border-bottom:1px solid #e8e0d5}')
expect(css).toContain('.settings-row{min-height:62px;padding:6px 0;border-top:0;border-bottom:1px solid #e8e0d5;')
expect(css).toContain('.settings-topbar{margin-bottom:0}')
expect(css).toContain('.topbar>.settings-refresh{grid-area:filter}')
expect(css).not.toContain('.topbar>.settings-refresh{grid-area:filter}')
expect(css).toContain('@media(max-width:720px){main:has(>.mvp-view .settings-sections){padding-left:29px;padding-right:29px;padding-bottom:calc(102px + env(safe-area-inset-bottom))}')
expect(css).toContain('.settings-sections{width:100%;padding-top:23px;padding-bottom:0}')
expect(css).toContain('.settings-heading h1{font-size:24px;line-height:1.1;font-weight:700}')
@@ -288,7 +289,7 @@ describe('solid cream material system', () => {
})
it('keeps controls solid, focus visible, mobile targets safe, and motion reducible', () => {
expect(css).toContain('input,select,textarea,.search{background:var(--surface-raised)')
expect(css).toContain('input,select,textarea{background:var(--surface-raised)')
expect(css).toContain(':focus-visible{outline:3px solid var(--focus-ring)')
expect(css).toContain('@media(max-width:930px){.bottom{left:0;right:0;bottom:0;height:calc(56px + var(--safe-area-bottom));')
expect(css).toContain('border:0;border-top:1px solid var(--border-cream);border-radius:0;padding:4px 10px var(--safe-area-bottom)')
@@ -414,13 +415,18 @@ describe('approved UI detail direction', () => {
expect(countdownPanel).toContain('<p>{{primaryDate(focusItem)}}</p>')
})
it('uses the real Memo search state in its toggle name', () => {
expect(readFileSync('src/MemoPanel.vue', 'utf8')).toContain(':aria-label="mobileSearchOpen ? \'收起搜索备忘录\' : \'展开搜索备忘录\'"')
it('does not expose task or memo search controls', () => {
expect(app).not.toContain('task-search-panel')
expect(app).not.toContain('mobileSearchOpen')
expect(readFileSync('src/MemoPanel.vue', 'utf8')).not.toContain('mobileSearchOpen')
expect(readFileSync('src/MemoPanel.vue', 'utf8')).not.toContain('搜索备忘录')
})
it('keeps refresh neutral and at least 44px', () => {
expect(css).toContain('.topbar-refresh{width:44px;height:44px;min-width:44px;border-radius:50%;color:var(--text-secondary)}')
expect(css).not.toContain('.topbar-refresh:hover:not(:disabled){background:#fff7eb;color:var(--accent)}')
it('does not expose manual refresh controls', () => {
expect(app).not.toContain('topbar-refresh')
expect(app).not.toContain('refreshCurrentView')
expect(app).not.toContain('aria-label="刷新当前页面"')
expect(css).not.toContain('.topbar-refresh{')
})
})
@@ -751,7 +757,7 @@ describe('task and habit row decoration', () => {
it('shows task drag handles only in an explicit available reorder mode', () => {
expect(app).toContain('const taskReorderMode = ref(false)')
expect(app).toContain("const taskReorderAvailable = computed(() => activeView.value === 'tasks' && !query.value && totalPages.value === 1 && taskTree.value.length > 1)")
expect(app).toContain("const taskReorderAvailable = computed(() => activeView.value === 'tasks' && totalPages.value === 1 && taskTree.value.length > 1)")
expect(app).toContain('class="soft-button reorder-mode-toggle task-reorder-toggle"')
expect(app).toContain("{{ taskReorderMode ? '完成' : '调整顺序' }}")
expect(app).toContain('v-if="taskReorderMode" class="drag-handle task-drag-handle"')
@@ -934,20 +940,15 @@ describe('task and habit row decoration', () => {
const topbar = app.slice(app.indexOf('<header class="topbar"'), app.indexOf('</header>', app.indexOf('<header class="topbar"')))
expect(topbar.match(/<CompletedFilterPill/g) ?? []).toHaveLength(0)
expect(topbar).not.toContain('topbar-filter')
expect(app).toContain("v-if=\"['today', 'tasks', 'upcoming', 'habits'].includes(activeView)\"")
expect(app).not.toContain("v-if=\"['today', 'tasks', 'upcoming', 'habits'].includes(activeView)\" class=\"topbar-actions\"")
expect(app).toContain('class="today-inline-filter"')
expect(app).toContain('class="list-inline-filter"')
expect(mvpPanel).toContain('class="completed-filter-pill habit-inline-filter"')
expect(app).toContain('v-model="showCompleted"')
expect(app).toContain('class="topbar-actions"')
expect(app).toContain('topbar-refresh')
expect(app).toContain('aria-label="刷新当前页面"')
expect(app).toContain('@click="refreshCurrentView"')
expect(app).toContain(':class="{spinning:refreshing}"')
expect(app).toContain(':disabled="refreshing || loading"')
expect(app).toContain("else if (activeView.value === 'today') await Promise.all([refreshAll(), habitComposer.value?.refreshHabits()])")
expect(app).toContain("if (activeView.value === 'habits') await habitComposer.value?.refreshHabits()")
expect(mvpPanel).toContain('defineExpose({ openHabitComposer, refreshHabits: loadHabits, refreshSettings: loadSettings })')
expect(app).not.toContain('class="topbar-actions"')
expect(app).not.toContain('topbar-refresh')
expect(app).not.toContain('aria-label="刷新当前页面"')
expect(app).not.toContain('refreshCurrentView')
expect(app).toContain("readStoredBoolean(window.localStorage, SHOW_COMPLETED_STORAGE_KEY, true)")
expect(app).toContain("writeStoredBoolean(window.localStorage, SHOW_COMPLETED_STORAGE_KEY, value)")
expect(app).toContain(':show-completed="showCompleted"')
@@ -976,26 +977,18 @@ describe('task and habit row decoration', () => {
expect(css).not.toContain('@media(max-width:930px){main{scrollbar-width:none}')
})
it('uses a full-width search row and hides it behind mobile pull-to-reveal', () => {
it('uses the compact two-column topbar without search or refresh affordances', () => {
expect(css).toContain('main{container-type:inline-size;')
expect(css).toContain('.topbar{display:grid;grid-template-columns:44px minmax(0,1fr) auto;grid-template-areas:"menu title filter" "search search search";')
expect(css).toContain('.search-reveal{grid-area:search;width:100%;min-width:0}')
expect(css).toContain('.topbar .search{width:100%;margin:0}')
expect(css).toContain('.topbar{display:grid;grid-template-columns:44px minmax(0,1fr);grid-template-areas:"menu title";')
expect(css).toContain('.topbar-title{grid-area:title;min-width:0;width:100%}')
expect(css).toContain('.topbar h1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;')
expect(css).toContain('.topbar-filter{justify-self:end;')
expect(css).toContain('.topbar-actions{grid-area:filter;justify-self:end;display:flex;align-items:center;gap:8px}')
expect(css).toContain('.topbar-refresh{width:44px;height:44px;')
expect(css).toContain('.topbar-refresh.spinning svg{animation:topbar-refresh-spin .7s linear infinite}')
expect(app.indexOf('class="topbar-actions"')).toBeLessThan(app.indexOf('class="search-reveal"'))
expect(app).toContain('@touchstart="startSearchPull"')
expect(app).toContain('@touchmove="moveSearchPull"')
expect(app).toContain('@touchend="finishSearchPull"')
expect(app).toContain('ref="searchInput"')
expect(app).toContain('class="search-pull-hint"')
expect(css).toContain('.search-reveal{max-height:0;opacity:0;overflow:hidden;visibility:hidden;pointer-events:none;')
expect(css).toContain('.search-reveal.mobile-search-open{max-height:52px;opacity:1;visibility:visible;pointer-events:auto;transform:none;overflow:visible}')
expect(css).toContain('.search-reveal.mobile-search-pulling{max-height:var(--search-pull);')
expect(app).not.toContain('task-search-panel')
expect(app).not.toContain('search-reveal')
expect(app).not.toContain('startSearchPull')
expect(app).not.toContain('searchInput')
expect(app).not.toContain('topbar-refresh')
expect(css).not.toContain('.search-reveal{')
expect(css).not.toContain('.topbar-refresh{')
const mobileLayout = css.slice(css.indexOf('@media(max-width:930px){.shell'))
expect(mobileLayout).toContain('.completed-filter-pill{min-width:138px;height:44px')
expect(css).not.toContain('width:min(260px,100%)')
@@ -1018,7 +1011,7 @@ describe('task and habit row decoration', () => {
})
it('uses a compact hidden-completed notice only on Today', () => {
expect(app).toContain("v-if=\"activeView==='today' && !query && hiddenCompletedTaskCount > 0 && !visibleTasks.length && !loading\" class=\"today-filtered-empty-note\"")
expect(app).toContain("v-if=\"activeView==='today' && hiddenCompletedTaskCount > 0 && !visibleTasks.length && !loading\" class=\"today-filtered-empty-note\"")
expect(app).toContain('已隐藏已完成任务')
expect(app).toContain('@click="showCompleted=true">显示</button>')
expect(app).toContain("v-else-if=\"!visibleTasks.length&&!loading\" class=\"empty\"")
@@ -1026,9 +1019,10 @@ describe('task and habit row decoration', () => {
expect(css).toContain('@media(max-width:930px){.today-filtered-empty-note{min-height:44px;')
})
it('distinguishes hidden completed items from true and search empty states', () => {
it('distinguishes hidden completed items from the true empty state', () => {
expect(app).toContain('const hiddenCompletedTaskCount = ref(0)')
expect(app).toContain("query ? '没有匹配的任务' : hiddenCompletedTaskCount > 0 ? '已完成任务已隐藏' : '这里还很安静'")
expect(app).toContain("hiddenCompletedTaskCount > 0 ? '已完成任务已隐藏' : '这里还很安静'")
expect(app).not.toContain('没有匹配的任务')
expect(mvpPanel).toContain("!showCompleted && todayHabits.length ? '已完成的习惯已隐藏。'")
expect(mvpPanel).toContain("!showCompleted && habits.length ? '已完成的习惯已隐藏。'")
})