auto close seletor
This commit is contained in:
35
src/App.vue
35
src/App.vue
@@ -60,11 +60,32 @@ let store: any = null;
|
||||
let captureUnlisten: any = null;
|
||||
|
||||
// --- Custom Picker States ---
|
||||
const calendarRef = ref<HTMLElement | null>(null);
|
||||
const startTimePickerRef = ref<HTMLElement | null>(null);
|
||||
const endTimePickerRef = ref<HTMLElement | null>(null);
|
||||
const tagSelectRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const isCalendarOpen = ref(false);
|
||||
const calendarMonth = ref(new Date());
|
||||
const isStartTimeOpen = ref(false);
|
||||
const isEndTimeOpen = ref(false);
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (isCalendarOpen.value && calendarRef.value && !calendarRef.value.contains(target)) {
|
||||
isCalendarOpen.value = false;
|
||||
}
|
||||
if (isStartTimeOpen.value && startTimePickerRef.value && !startTimePickerRef.value.contains(target)) {
|
||||
isStartTimeOpen.value = false;
|
||||
}
|
||||
if (isEndTimeOpen.value && endTimePickerRef.value && !endTimePickerRef.value.contains(target)) {
|
||||
isEndTimeOpen.value = false;
|
||||
}
|
||||
if (isTagSelectOpen.value && tagSelectRef.value && !tagSelectRef.value.contains(target)) {
|
||||
isTagSelectOpen.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const openStartTimePicker = async () => {
|
||||
isStartTimeOpen.value = !isStartTimeOpen.value;
|
||||
isEndTimeOpen.value = false;
|
||||
@@ -105,6 +126,7 @@ const selectCalendarDate = (date: Date) => {
|
||||
|
||||
// --- Logic ---
|
||||
onMounted(async () => {
|
||||
window.addEventListener('mousedown', handleClickOutside);
|
||||
store = await load("config.json");
|
||||
const path = await store.get("savePath");
|
||||
const dPath = await store.get("dbPath");
|
||||
@@ -125,7 +147,10 @@ onMounted(async () => {
|
||||
captureUnlisten = await listen("refresh-timeline", () => { loadTimeline(); });
|
||||
});
|
||||
|
||||
onUnmounted(() => { if (captureUnlisten) captureUnlisten(); });
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('mousedown', handleClickOutside);
|
||||
if (captureUnlisten) captureUnlisten();
|
||||
});
|
||||
|
||||
const selectFolder = async () => { const s = await open({ directory: true }); if (s) savePath.value = s as string; };
|
||||
const selectDBFile = async () => { const s = await open({ filters: [{ name: "SQLite", extensions: ["db"] }] }); if (s) dbPath.value = s as string; };
|
||||
@@ -355,7 +380,7 @@ const isTagSelectOpen = ref(false);
|
||||
<div class="w-80 bg-[#F8FAFD] border-r border-[#E5E5E7] flex flex-col select-none relative">
|
||||
<div class="p-6 bg-[#F8FAFD]/80 backdrop-blur-md sticky top-0 z-20 border-b border-[#E5E5E7]/50">
|
||||
<div class="flex items-center justify-between mb-4"><h2 class="text-lg font-bold">历史活动</h2><button @click="loadTimeline(true); loadEvents()" class="p-2 hover:bg-white rounded-xl text-[#86868B]"><RefreshCw :size="18" /></button></div>
|
||||
<div class="relative group">
|
||||
<div ref="calendarRef" class="relative group">
|
||||
<button @click="isCalendarOpen = !isCalendarOpen" class="w-full bg-white border border-[#E5E5E7] rounded-xl pl-11 pr-4 py-2.5 text-sm font-bold text-left flex items-center hover:bg-[#F2F2F7] transition-all">
|
||||
<Calendar :size="16" class="absolute left-4 text-[#86868B]" />
|
||||
{{ currentDate }}
|
||||
@@ -415,7 +440,7 @@ const isTagSelectOpen = ref(false);
|
||||
<div class="p-10 space-y-8">
|
||||
<div class="flex gap-4">
|
||||
<!-- Start Time Custom Picker -->
|
||||
<div class="flex-1 space-y-1 relative">
|
||||
<div ref="startTimePickerRef" class="flex-1 space-y-1 relative">
|
||||
<label class="text-[10px] font-bold text-[#86868B]">开始时间</label>
|
||||
<button @click="openStartTimePicker"
|
||||
class="w-full h-12 bg-[#F2F2F7] rounded-xl px-4 flex items-center justify-center gap-2 hover:bg-[#E5E5E7] transition-all border border-transparent focus:border-[#007AFF]/30">
|
||||
@@ -443,7 +468,7 @@ const isTagSelectOpen = ref(false);
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Time Custom Picker -->
|
||||
<div class="flex-1 space-y-1 relative">
|
||||
<div ref="endTimePickerRef" class="flex-1 space-y-1 relative">
|
||||
<label class="text-[10px] font-bold text-[#86868B]">结束时间</label>
|
||||
<button @click="openEndTimePicker"
|
||||
class="w-full h-12 bg-[#F2F2F7] rounded-xl px-4 flex items-center justify-center gap-2 hover:bg-[#E5E5E7] transition-all border border-transparent focus:border-[#007AFF]/30">
|
||||
@@ -504,7 +529,7 @@ const isTagSelectOpen = ref(false);
|
||||
<label class="text-[10px] font-bold text-[#86868B] ml-1">标签名称</label>
|
||||
<input v-model="newTagName" placeholder="输入名称..." class="w-full bg-white rounded-xl px-4 py-2.5 text-sm outline-none border border-transparent focus:border-[#007AFF] transition-all" />
|
||||
</div>
|
||||
<div class="space-y-1 relative">
|
||||
<div ref="tagSelectRef" class="space-y-1 relative">
|
||||
<label class="text-[10px] font-bold text-[#86868B] ml-1">父级标签</label>
|
||||
<button @click="isTagSelectOpen = !isTagSelectOpen" class="w-full bg-white rounded-xl px-4 py-2.5 text-sm text-left flex justify-between items-center border border-transparent focus:border-[#007AFF] transition-all">
|
||||
<span>{{ getTagName(newTagParent) }}</span>
|
||||
|
||||
Reference in New Issue
Block a user