mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-22 05:34:04 +02:00
added time stamps
This commit is contained in:
parent
15b6dd91a1
commit
2093ea7274
2 changed files with 125 additions and 61 deletions
170
app.vue
170
app.vue
|
@ -26,15 +26,19 @@
|
||||||
</div>
|
</div>
|
||||||
<OverlayScrollbarsComponent class="results" ref="resultsContainer"
|
<OverlayScrollbarsComponent class="results" ref="resultsContainer"
|
||||||
:options="{ scrollbars: { autoHide: 'scroll' } }">
|
:options="{ scrollbars: { autoHide: 'scroll' } }">
|
||||||
<div v-for="(item, index) in filteredHistory" :key="item.id"
|
<template v-for="(group, groupIndex) in groupedHistory" :key="groupIndex">
|
||||||
:class="['result clothoid-corner', { 'selected': index === selectedIndex }]" @click="selectItem(index)"
|
<div class="time-separator">{{ group.label }}</div>
|
||||||
:ref="el => { if (index === selectedIndex) selectedElement = el }">
|
<div v-for="(item, index) in group.items" :key="item.id"
|
||||||
|
:class="['result clothoid-corner', { 'selected': isSelected(groupIndex, index) }]"
|
||||||
|
@click="selectItem(groupIndex, index)"
|
||||||
|
:ref="el => { if (isSelected(groupIndex, index)) selectedElement = el }">
|
||||||
<FileIcon />
|
<FileIcon />
|
||||||
{{ truncateContent(item.content) }}
|
{{ truncateContent(item.content) }}
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
<OverlayScrollbarsComponent class="content">
|
<OverlayScrollbarsComponent class="content">
|
||||||
{{ filteredHistory[selectedIndex]?.content || '' }}
|
{{ selectedItem?.content || '' }}
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
<Noise />
|
<Noise />
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,78 +60,95 @@ import { listen } from '@tauri-apps/api/event';
|
||||||
const db = ref(null);
|
const db = ref(null);
|
||||||
const history = ref([]);
|
const history = ref([]);
|
||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
const selectedIndex = ref(0);
|
const selectedGroupIndex = ref(0);
|
||||||
|
const selectedItemIndex = ref(0);
|
||||||
const resultsContainer = ref(null);
|
const resultsContainer = ref(null);
|
||||||
const selectedElement = ref(null);
|
const selectedElement = ref(null);
|
||||||
const os = platform();
|
const os = platform();
|
||||||
|
|
||||||
const filteredHistory = computed(() => {
|
const groupedHistory = computed(() => {
|
||||||
if (!searchQuery.value) return history.value;
|
const now = new Date();
|
||||||
return history.value
|
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||||
.filter(item => item.content.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
const yesterday = new Date(today);
|
||||||
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
const thisWeek = new Date(today);
|
||||||
|
thisWeek.setDate(thisWeek.getDate() - 7);
|
||||||
|
const thisYear = new Date(now.getFullYear(), 0, 1);
|
||||||
|
|
||||||
|
const groups = [
|
||||||
|
{ label: 'Today', items: [] },
|
||||||
|
{ label: 'Yesterday', items: [] },
|
||||||
|
{ label: 'This Week', items: [] },
|
||||||
|
{ label: 'This Year', items: [] },
|
||||||
|
{ label: 'Last Year', items: [] },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filteredItems = searchQuery.value
|
||||||
|
? history.value.filter(item => item.content.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
||||||
|
: history.value;
|
||||||
|
|
||||||
|
filteredItems.forEach(item => {
|
||||||
|
const itemDate = new Date(item.timestamp);
|
||||||
|
if (itemDate >= today) {
|
||||||
|
groups[0].items.push(item);
|
||||||
|
} else if (itemDate >= yesterday) {
|
||||||
|
groups[1].items.push(item);
|
||||||
|
} else if (itemDate >= thisWeek) {
|
||||||
|
groups[2].items.push(item);
|
||||||
|
} else if (itemDate >= thisYear) {
|
||||||
|
groups[3].items.push(item);
|
||||||
|
} else {
|
||||||
|
groups[4].items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return groups.filter(group => group.items.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedItem = computed(() => {
|
||||||
|
const group = groupedHistory.value[selectedGroupIndex.value];
|
||||||
|
return group ? group.items[selectedItemIndex.value] : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSelected = (groupIndex, itemIndex) => {
|
||||||
|
return selectedGroupIndex.value === groupIndex && selectedItemIndex.value === itemIndex;
|
||||||
|
};
|
||||||
|
|
||||||
const searchHistory = () => {
|
const searchHistory = () => {
|
||||||
selectedIndex.value = 0;
|
selectedGroupIndex.value = 0;
|
||||||
|
selectedItemIndex.value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectNext = () => {
|
const selectNext = () => {
|
||||||
if (selectedIndex.value < filteredHistory.value.length - 1) {
|
const currentGroup = groupedHistory.value[selectedGroupIndex.value];
|
||||||
selectedIndex.value++;
|
if (selectedItemIndex.value < currentGroup.items.length - 1) {
|
||||||
scrollToSelectedItem();
|
selectedItemIndex.value++;
|
||||||
|
} else if (selectedGroupIndex.value < groupedHistory.value.length - 1) {
|
||||||
|
selectedGroupIndex.value++;
|
||||||
|
selectedItemIndex.value = 0;
|
||||||
}
|
}
|
||||||
|
scrollToSelectedItem();
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectPrevious = () => {
|
const selectPrevious = () => {
|
||||||
if (selectedIndex.value > 0) {
|
if (selectedItemIndex.value > 0) {
|
||||||
selectedIndex.value--;
|
selectedItemIndex.value--;
|
||||||
|
} else if (selectedGroupIndex.value > 0) {
|
||||||
|
selectedGroupIndex.value--;
|
||||||
|
selectedItemIndex.value = groupedHistory.value[selectedGroupIndex.value].items.length - 1;
|
||||||
|
}
|
||||||
scrollToSelectedItem();
|
scrollToSelectedItem();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const scrollToSelectedItem = () => {
|
const selectItem = (groupIndex, itemIndex) => {
|
||||||
nextTick(() => {
|
selectedGroupIndex.value = groupIndex;
|
||||||
if (selectedElement.value && resultsContainer.value) {
|
selectedItemIndex.value = itemIndex;
|
||||||
const osInstance = resultsContainer.value.osInstance();
|
|
||||||
const { viewport } = osInstance.elements();
|
|
||||||
const element = selectedElement.value;
|
|
||||||
|
|
||||||
const viewportRect = viewport.getBoundingClientRect();
|
|
||||||
const elementRect = element.getBoundingClientRect();
|
|
||||||
|
|
||||||
const isAbove = elementRect.top < viewportRect.top;
|
|
||||||
const isBelow = elementRect.bottom > viewportRect.bottom - 8;
|
|
||||||
|
|
||||||
if (isAbove || isBelow) {
|
|
||||||
let scrollOffset;
|
|
||||||
|
|
||||||
if (isAbove && selectedIndex.value === 0) {
|
|
||||||
scrollOffset = elementRect.top - viewportRect.top - 14;
|
|
||||||
} else if (isAbove) {
|
|
||||||
scrollOffset = elementRect.top - viewportRect.top - 8;
|
|
||||||
} else {
|
|
||||||
scrollOffset = elementRect.bottom - viewportRect.bottom + 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
viewport.scrollBy({
|
|
||||||
top: scrollOffset,
|
|
||||||
behavior: 'smooth'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectItem = (index) => {
|
|
||||||
selectedIndex.value = index;
|
|
||||||
scrollToSelectedItem();
|
scrollToSelectedItem();
|
||||||
};
|
};
|
||||||
|
|
||||||
const pasteSelectedItem = async () => {
|
const pasteSelectedItem = async () => {
|
||||||
const selectedItem = filteredHistory.value[selectedIndex.value];
|
if (selectedItem.value) {
|
||||||
if (selectedItem) {
|
await writeText(selectedItem.value.content);
|
||||||
await writeText(selectedItem.content);
|
|
||||||
await hideApp();
|
await hideApp();
|
||||||
await invoke("simulate_paste");
|
await invoke("simulate_paste");
|
||||||
}
|
}
|
||||||
|
@ -164,10 +185,45 @@ const showApp = async () => {
|
||||||
await refreshHistory();
|
await refreshHistory();
|
||||||
await app.show();
|
await app.show();
|
||||||
await window.getCurrent().show();
|
await window.getCurrent().show();
|
||||||
selectedIndex.value = 0;
|
selectedGroupIndex.value = 0;
|
||||||
|
selectedItemIndex.value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(selectedIndex, scrollToSelectedItem);
|
const scrollToSelectedItem = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (selectedElement.value && resultsContainer.value) {
|
||||||
|
const osInstance = resultsContainer.value.osInstance();
|
||||||
|
const { viewport } = osInstance.elements();
|
||||||
|
const element = selectedElement.value;
|
||||||
|
|
||||||
|
const viewportRect = viewport.getBoundingClientRect();
|
||||||
|
const elementRect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
const isAbove = elementRect.top < viewportRect.top;
|
||||||
|
const isBelow = elementRect.bottom > viewportRect.bottom - 8;
|
||||||
|
|
||||||
|
if (isAbove || isBelow) {
|
||||||
|
let scrollOffset;
|
||||||
|
|
||||||
|
if (isAbove && selectedItemIndex.value === 0 && selectedGroupIndex.value === 0) {
|
||||||
|
scrollOffset = elementRect.top - viewportRect.top - 36;
|
||||||
|
} else if (isAbove) {
|
||||||
|
scrollOffset = elementRect.top - viewportRect.top - 8;
|
||||||
|
} else {
|
||||||
|
scrollOffset = elementRect.bottom - viewportRect.bottom + 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewport.scrollBy({
|
||||||
|
top: scrollOffset,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch([selectedGroupIndex, selectedItemIndex], scrollToSelectedItem);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -89,7 +89,6 @@ body,
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding-inline: 8px;
|
padding-inline: 8px;
|
||||||
padding-top: 14px;
|
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -112,6 +111,15 @@ body,
|
||||||
background-color: $divider;
|
background-color: $divider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.time-separator{
|
||||||
|
font-size: 12px;
|
||||||
|
color: $text2;
|
||||||
|
font-family: SFRoundedSemiBold;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
padding-top: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue