style: simplify mobile task views
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { Archive, FileText, Search } from 'lucide-vue-next'
|
||||
import { Archive, FileText, Search, X } from 'lucide-vue-next'
|
||||
import MemoRow, { type MemoListItem } from './components/MemoRow.vue'
|
||||
import MemoEditor, { type MemoEditorValue, type MemoRecord } from './components/MemoEditor.vue'
|
||||
import AppDialog, { type AppDialogOptions } from './components/AppDialog.vue'
|
||||
@@ -22,7 +22,10 @@ const selectedToken = ref(0)
|
||||
const editor = ref<InstanceType<typeof MemoEditor> | null>(null)
|
||||
const appDialog = ref<{ show: (options: AppDialogOptions) => Promise<boolean | string | null> } | null>(null)
|
||||
const searchInput = ref<HTMLInputElement | null>(null)
|
||||
const mobileDetail = ref(window.innerWidth <= 930)
|
||||
const searchToggle = ref<HTMLButtonElement | null>(null)
|
||||
const mobileLayout = ref(window.innerWidth <= 930)
|
||||
const mobileDetail = ref(mobileLayout.value)
|
||||
const mobileSearchOpen = ref(false)
|
||||
let detailOpener: HTMLElement | null = null
|
||||
let timer: number | undefined
|
||||
let generation = 0
|
||||
@@ -182,7 +185,14 @@ function removeItem(id: string, selectionToken: number) {
|
||||
void nextTick(() => (opener?.isConnected ? opener : searchInput.value)?.focus())
|
||||
}
|
||||
function removeRestoredItem(memo: MemoRecord, selectionToken: number) { removeItem(memo.id, selectionToken) }
|
||||
function updateLayout() { mobileDetail.value = window.innerWidth <= 930 }
|
||||
function openMobileSearch() { mobileSearchOpen.value = true; void nextTick(() => searchInput.value?.focus()) }
|
||||
function closeMobileSearch() { mobileSearchOpen.value = false; void nextTick(() => searchToggle.value?.focus()) }
|
||||
function handleSearchKeydown(event: KeyboardEvent) { if (event.key === 'Escape' && mobileLayout.value) { event.preventDefault(); closeMobileSearch() } }
|
||||
function clearSearch() { query.value = ''; void nextTick(() => searchInput.value?.focus()) }
|
||||
function updateLayout() {
|
||||
mobileLayout.value = window.innerWidth <= 930
|
||||
mobileDetail.value = mobileLayout.value
|
||||
}
|
||||
watch(query, () => {
|
||||
generation += 1
|
||||
loading.value = false
|
||||
@@ -201,7 +211,8 @@ defineExpose({ createMemo, requestClose: () => editor.value?.requestClose(), dir
|
||||
<div class="memo-panel__main" :inert="selected && mobileDetail ? true : undefined">
|
||||
<div class="memo-toolbar">
|
||||
<div class="memo-scope" role="tablist" aria-label="备忘录范围"><button role="tab" data-scope="active" :aria-selected="scope==='active'" @click="setScope('active')">活动</button><button role="tab" data-scope="trash" :aria-selected="scope==='trash'" @click="setScope('trash')"><Archive/>回收站</button></div>
|
||||
<label class="memo-search"><Search/><input ref="searchInput" v-model="query" aria-label="搜索备忘录" placeholder="搜索标题或正文…"></label>
|
||||
<button ref="searchToggle" class="memo-search-toggle" type="button" aria-label="展开搜索备忘录" :aria-expanded="mobileLayout ? mobileSearchOpen : true" aria-controls="memo-search-panel" @click="mobileSearchOpen ? closeMobileSearch() : openMobileSearch()"><Search/></button>
|
||||
<div id="memo-search-panel" class="memo-search-panel" :class="{'is-open':mobileSearchOpen}" :hidden="mobileLayout && !mobileSearchOpen"><label class="memo-search"><Search/><input id="memo-search-input" ref="searchInput" v-model="query" aria-label="搜索备忘录" placeholder="搜索标题或正文…" @keydown="handleSearchKeydown"></label><button v-if="query" type="button" class="memo-search-clear" aria-label="清空搜索" @click="clearSearch"><X/></button></div>
|
||||
</div>
|
||||
<p v-if="error" class="memo-error" role="alert">{{error}} <button class="link" @click="load()">重试</button></p>
|
||||
<div v-if="loading && !items.length" class="memo-state"><span class="loader"/>正在载入备忘录…</div>
|
||||
|
||||
Reference in New Issue
Block a user