This commit is contained in:
@@ -3,7 +3,7 @@ import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import {
|
||||
ArchiveRestore, CalendarDays, CalendarHeart, Check, ChevronDown, ChevronRight, Folder,
|
||||
GripVertical, Inbox, ListChecks, ListTodo, Menu, Pencil, Plus, Search,
|
||||
Settings, Trash2, X, Repeat2, Ellipsis,
|
||||
Settings, Trash2, X, Repeat2,
|
||||
} from 'lucide-vue-next'
|
||||
import { filterTasks, fromDateTimeLocal, groupTaskTree, renderMarkdown, toDateTimeLocal } from './lib/task-utils'
|
||||
import { defaultView, isTaskView, nextTotalAfterLocalTaskAdd, quickTaskFields, shouldToggleRowSwipe } from './lib/mvp-utils'
|
||||
@@ -565,8 +565,8 @@ onMounted(bootstrap)
|
||||
<div v-else class="paper"><ListChecks/><b>选中一个任务</b><p>日期、优先级、子任务和 Markdown 备注会出现在这里。</p></div>
|
||||
</aside>
|
||||
|
||||
<div v-if="mobileMore" class="more-mask" @click.self="mobileMore=false"><section id="mobile-more-menu" class="more-sheet" role="dialog" aria-modal="true" aria-label="更多导航"><div class="more-sheet-head"><b>更多</b><button class="icon" aria-label="关闭更多菜单" @click="mobileMore=false"><X/></button></div><button @click="switchView('settings')"><Settings/>设置与数据</button></section></div>
|
||||
<nav class="bottom" aria-label="主要导航"><button :class="{active:activeView==='today'}" @click="switchView('today')"><ListTodo/><span>今天</span></button><button :class="{active:activeView==='habits'}" @click="switchView('habits')"><Repeat2/><span>习惯</span></button><button :class="{active:activeView==='countdowns'}" @click="switchView('countdowns')"><CalendarHeart/><span>倒数日</span></button><button :class="{active:mobileMore||['tasks','upcoming','trash','settings'].includes(activeView)}" aria-haspopup="dialog" aria-controls="mobile-more-menu" :aria-expanded="mobileMore" @click="mobileMore=!mobileMore"><Ellipsis/><span>更多</span></button></nav>
|
||||
<div v-if="mobileMore" class="more-mask" @click.self="mobileMore=false;switchView('settings')"><section id="mobile-more-menu" class="more-sheet" role="dialog" aria-modal="true" aria-label="更多导航" @click.stop><div class="more-sheet-head"><b>更多</b><button class="icon" aria-label="关闭更多菜单" @click="mobileMore=false"><X/></button></div><button @click="switchView('settings')"><Settings/>设置与数据</button></section></div>
|
||||
<nav class="bottom" aria-label="主要导航"><button :class="{active:activeView==='today'}" @click="switchView('today')"><ListTodo/><span>今天</span></button><button :class="{active:activeView==='habits'}" @click="switchView('habits')"><Repeat2/><span>习惯</span></button><button :class="{active:activeView==='countdowns'}" @click="switchView('countdowns')"><CalendarHeart/><span>倒数日</span></button><button :class="{active:activeView==='tasks'||activeView==='upcoming'||activeView==='trash'||activeView==='settings'}" @click="switchView('settings')"><Settings/><span>设置</span></button></nav>
|
||||
<FloatingAddButton v-if="['tasks','today','upcoming','habits','countdowns'].includes(activeView)" :label="activeView==='habits' ? '添加习惯' : activeView==='countdowns' ? '添加倒数日' : '添加任务'" @activate="activateFloatingAdd" />
|
||||
<Transition name="task-compose">
|
||||
<div v-if="taskComposeOpen" class="task-compose-mask" @click.self="closeTaskCompose">
|
||||
|
||||
@@ -8,7 +8,7 @@ main{min-width:0;padding:27px 34px 50px;overflow:auto;background:linear-gradient
|
||||
.detail{min-width:0;border-left:1px solid var(--line);background:#faf7f0;overflow:auto}.detail-head{height:57px;display:flex;align-items:center;justify-content:space-between;padding:0 21px;border-bottom:1px solid var(--line);font-size:12px;font-weight:700;color:#80766a;text-transform:uppercase;letter-spacing:.08em}.paper{margin:22px;padding:28px 20px;min-height:180px;background:#fff;border:1px solid var(--line);border-radius:11px;box-shadow:0 4px 18px rgba(76,57,34,.05);display:grid;place-items:center;align-content:center;text-align:center;color:#8f8578}.paper svg{width:32px;height:32px;color:#ceb8a4;margin-bottom:12px}.paper b{color:#625b50}.paper p{font-size:13px;line-height:1.6}.detail-form{padding:19px;display:grid;gap:15px}.detail-title{display:flex;align-items:flex-start;gap:10px}.check.large{margin-top:8px;width:22px;height:22px;flex-basis:22px}.detail-title textarea{flex:1;border:0;background:transparent;resize:none;outline:none;font-size:19px;line-height:1.4;font-weight:700}.detail-form>label{grid-template-columns:80px 1fr;align-items:center}.detail-form>label input,.detail-form>label select{padding:8px}.field{display:grid;gap:7px}.field-label{display:flex;justify-content:space-between;align-items:center;font-size:12px;font-weight:700;color:#756d61}.hint{font-size:12px;color:#a49a8d}.markdown .field-label>span:last-child{display:flex;background:#eee7dc;padding:2px;border-radius:6px}.markdown .field-label button{border:0;background:transparent;padding:4px 8px;border-radius:5px;font-size:11px}.markdown .field-label button.active{background:#fff;color:var(--accent)}.markdown textarea{border:1px solid var(--line);background:#fff;border-radius:9px;padding:11px;resize:vertical;outline:none;font:13px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.markdown-preview{min-height:160px;padding:10px 12px;background:#fff;border:1px solid var(--line);border-radius:9px;font-size:13px;line-height:1.65;overflow-wrap:anywhere}.markdown-preview h1{font-size:20px}.markdown-preview h2{font-size:16px}.markdown-preview p{margin:8px 0}.markdown-preview code{background:#f2ece2;padding:2px 4px;border-radius:4px}.markdown-preview a{color:var(--accent)}.subtasks{display:grid;gap:5px}.subtask-detail{display:flex;align-items:center;gap:8px;border:0;background:#fff;padding:8px;border-radius:7px;text-align:left}.subtask-detail .check{pointer-events:none}.strike{text-decoration:line-through;color:var(--muted)}.detail-actions{display:flex;justify-content:space-between;align-items:center;padding-top:10px;border-top:1px solid var(--line)}.secondary{border:1px solid var(--line);background:#fff;padding:8px 11px;border-radius:8px;font-weight:650}.danger-text{border:0;background:transparent;color:var(--danger);display:flex;align-items:center;gap:5px;font-size:12px}.danger-text svg{width:14px}
|
||||
.toast,.error-toast{position:fixed;z-index:50;left:50%;bottom:24px;transform:translateX(-50%);background:#322d28;color:#fff;border-radius:9px;padding:10px 15px;box-shadow:var(--shadow);font-size:13px}.error-toast{background:var(--danger);display:flex;align-items:center;gap:10px}.error-toast button{border:0;background:transparent;color:#fff;padding:0}.toast-enter-active,.toast-leave-active{transition:.2s}.toast-enter-from,.toast-leave-to{opacity:0;transform:translate(-50%,8px)}
|
||||
@media(max-width:1050px){.shell{grid-template-columns:220px minmax(400px,1fr) 310px}main{padding-inline:24px}}
|
||||
@media(max-width:930px){.shell{height:100dvh;display:block;overflow:auto}.sidebar{position:fixed;z-index:50;display:flex;top:0;bottom:0;transition:transform .22s ease;box-shadow:var(--shadow);left:0;width:min(300px,86vw);transform:translateX(-105%)}.sidebar.open{transform:none}.detail{position:fixed;z-index:40;display:block;left:0;right:0;top:auto;bottom:0;width:100%;max-height:min(88dvh,760px);overflow:auto;background:#fffdf8;border:1px solid var(--line);border-bottom:0;border-radius:22px 22px 0 0;box-shadow:0 -14px 38px rgba(56,40,24,.2);transform:translateY(105%);transition:transform .22s ease;padding-bottom:max(16px,env(safe-area-inset-bottom))}.detail.open{transform:none}.detail-head{position:sticky;z-index:2;top:0;height:62px;background:#fffdf8;border-bottom:1px solid var(--line);padding:0 18px}.detail-head .icon{display:grid;width:42px;height:42px;background:var(--accent-soft);color:var(--accent);border-radius:50%}.detail-form{padding:18px}.detail-title textarea{font-size:21px}.more-mask{position:fixed;z-index:45;inset:0;background:rgba(45,38,31,.32);display:flex;align-items:flex-end}.more-sheet{width:100%;background:#fffdf8;border-radius:22px 22px 0 0;padding:14px 16px max(22px,env(safe-area-inset-bottom));display:grid;gap:6px}.more-sheet-head{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 8px}.more-sheet>button{display:flex;align-items:center;gap:12px;border:0;background:#fff;padding:13px;border-radius:12px;text-align:left}.scrim{position:fixed;z-index:35;inset:0;background:rgba(45,38,31,.32)}.mobile-only{display:grid}main{min-height:100dvh;padding:20px 17px 112px}.topbar h1{font-size:24px;margin:0 0 17px}.search{width:auto;margin-bottom:13px;padding:8px}.search input{width:90px}.search kbd{display:none}.row-actions{position:static;opacity:1;pointer-events:auto}.row-actions button{padding:7px;min-height:34px}.list-row{padding:6px 4px}.archived-row{padding:9px 7px;border:1px dashed #e0cfae;border-radius:8px;color:#8a6d3b;background:#fbf3e2}.archived-row .list-row-main{padding-left:14px}.archived-row .list-row-main>svg{color:#c9a45c}.bottom{display:flex;position:fixed;z-index:15;left:0;right:0;bottom:0;justify-content:space-around;background:rgba(255,253,248,.96);border-top:1px solid var(--line);padding:8px 5px max(8px,env(safe-area-inset-bottom));box-shadow:0 -5px 18px rgba(79,59,34,.06)}.bottom button{min-height:44px;min-width:60px;border:0;background:transparent;color:#81786d;display:grid;place-items:center;gap:2px;font-size:10px}.bottom button.active{color:var(--accent);font-weight:700}.bottom svg{width:20px}.toast,.error-toast{bottom:142px}.task-row{padding-inline:2px}.subtask{padding-left:35px}.ghost{opacity:.45}}
|
||||
@media(max-width:930px){.shell{height:100dvh;display:block;overflow:auto}.sidebar{position:fixed;z-index:50;display:flex;top:0;bottom:0;transition:transform .22s ease;box-shadow:var(--shadow);left:0;width:min(300px,86vw);transform:translateX(-105%)}.sidebar.open{transform:none}.detail{position:fixed;z-index:40;display:block;left:0;right:0;top:auto;bottom:0;width:100%;max-height:min(88dvh,760px);overflow:auto;background:#fffdf8;border:1px solid var(--line);border-bottom:0;border-radius:22px 22px 0 0;box-shadow:0 -14px 38px rgba(56,40,24,.2);transform:translateY(105%);transition:transform .22s ease;padding-bottom:max(16px,env(safe-area-inset-bottom))}.detail.open{transform:none}.detail-head{position:sticky;z-index:2;top:0;height:62px;background:#fffdf8;border-bottom:1px solid var(--line);padding:0 18px}.detail-head .icon{display:grid;width:42px;height:42px;background:var(--accent-soft);color:var(--accent);border-radius:50%}.detail-form{padding:18px}.detail-title textarea{font-size:21px}.more-mask{position:fixed;z-index:45;inset:0;background:rgba(45,38,31,.32);display:flex;align-items:flex-end}.more-sheet{width:100%;background:#fffdf8;border-radius:22px 22px 0 0;padding:14px 16px max(22px,env(safe-area-inset-bottom));display:grid;gap:6px}.more-sheet-head{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 8px}.more-sheet>button{display:flex;align-items:center;gap:12px;border:0;background:#fff;padding:13px;border-radius:12px;text-align:left}.scrim{position:fixed;z-index:35;inset:0;background:rgba(45,38,31,.32);display:block}.mobile-only{display:grid}main{min-height:100dvh;padding:20px 17px 112px}.topbar h1{font-size:24px;margin:0 0 17px}.search{width:auto;margin-bottom:13px;padding:8px}.search input{width:90px}.search kbd{display:none}.row-actions{position:static;opacity:1;pointer-events:auto}.row-actions button{padding:7px;min-height:34px}.list-row{padding:6px 4px}.archived-row{padding:9px 7px;border:1px dashed #e0cfae;border-radius:8px;color:#8a6d3b;background:#fbf3e2}.archived-row .list-row-main{padding-left:14px}.archived-row .list-row-main>svg{color:#c9a45c}.bottom{display:flex;position:fixed;z-index:15;left:0;right:0;bottom:0;justify-content:space-around;background:rgba(255,253,248,.96);border-top:1px solid var(--line);padding:8px 5px max(8px,env(safe-area-inset-bottom));box-shadow:0 -5px 18px rgba(79,59,34,.06)}.bottom button{min-height:44px;min-width:60px;border:0;background:transparent;color:#81786d;display:grid;place-items:center;gap:2px;font-size:10px}.bottom button.active{color:var(--accent);font-weight:700}.bottom svg{width:20px}.toast,.error-toast{bottom:142px}.task-row{padding-inline:2px}.subtask{padding-left:35px}.ghost{opacity:.45}}
|
||||
.mvp-view{display:grid;gap:16px;padding-bottom:36px}.view-intro{display:flex;align-items:end;justify-content:space-between;border-bottom:1px dashed var(--line);padding-bottom:12px}.view-intro h2{margin:2px 0 0;font-size:22px}.view-intro small,.view-intro>span{color:var(--muted);font-size:12px}.tool-card,.empty-panel{background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px;box-shadow:0 3px 14px rgba(81,61,38,.05)}.soft-button,.primary-small,.danger-button,.file-button{min-height:44px;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 11px;font-size:12px}.soft-button svg,.file-button svg{width:15px}.primary-small{background:var(--accent);border-color:var(--accent);color:#fff}.danger-button{color:var(--danger);border-color:#e5b7ad}.habit-list{display:grid;gap:10px}.tool-card h3{margin:0 0 4px}
|
||||
|
||||
.habit-row{border-left:0;--swipe-x:0px;display:flex;align-items:center;gap:8px;background:#fff;border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line);border-radius:14px;padding:5px 5px 5px 12px;box-shadow:0 3px 14px rgba(81,61,38,.05);transition:border-color .15s,box-shadow .15s,transform .18s ease;position:relative;overflow:hidden;isolation:isolate}
|
||||
|
||||
@@ -8,11 +8,26 @@ const countdownPanel = readFileSync('src/CountdownPanel.vue', 'utf8')
|
||||
const floatingAdd = readFileSync('src/components/FloatingAddButton.vue', 'utf8')
|
||||
|
||||
describe('mobile navigation styles', () => {
|
||||
it('renames the bottom More tab to a direct Settings tab', () => {
|
||||
expect(app).not.toContain('aria-controls="mobile-more-menu"')
|
||||
expect(app).not.toContain('<Ellipsis/><span>更多</span>')
|
||||
expect(app).toContain("<Settings/><span>设置</span>")
|
||||
expect(app).toContain("@click=\"switchView('settings')\"")
|
||||
expect(app).toContain('<span>设置</span>')
|
||||
})
|
||||
|
||||
it('keeps the mobile More sheet visible when it is rendered', () => {
|
||||
expect(css).not.toContain('.more-mask{display:none}')
|
||||
expect(css).toContain('@media(max-width:930px){.shell')
|
||||
expect(css).toContain('.more-mask{position:fixed;z-index:45;')
|
||||
})
|
||||
|
||||
it('lets the mobile sidebar scrim cover the outside area and stay below the sidebar', () => {
|
||||
expect(app).toContain('<div v-if="mobileSidebar || mobileDetail" class="scrim" @click="mobileSidebar=false;mobileDetail=false" />')
|
||||
expect(css).toContain('.sidebar{position:fixed;z-index:50;')
|
||||
expect(css).toContain('.scrim{position:fixed;z-index:35;inset:0;')
|
||||
expect(css).toMatch(/\.scrim\{position:fixed;z-index:35;[^}]*display:block/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('task and habit row decoration', () => {
|
||||
|
||||
Reference in New Issue
Block a user