mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-21 21:24:05 +02:00
added favicons and youtube thumbnails
This commit is contained in:
parent
b65121148f
commit
aa283284fe
2 changed files with 65 additions and 12 deletions
56
app.vue
56
app.vue
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="bg" @keydown.down.prevent="selectNext" @keydown.up.prevent="selectPrevious"
|
||||
@keydown.enter.prevent="pasteSelectedItem" @keydown.esc="hideApp" tabindex="0">
|
||||
<input v-model="searchQuery" @input="searchHistory" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
<input ref="searchInput" v-model="searchQuery" @input="searchHistory" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
class="search" type="text" placeholder="Type to filter entries...">
|
||||
<div class="bottom-bar">
|
||||
<div class="left">
|
||||
|
@ -32,13 +32,17 @@
|
|||
:class="['result clothoid-corner', { 'selected': isSelected(groupIndex, index) }]"
|
||||
@click="selectItem(groupIndex, index)"
|
||||
:ref="el => { if (isSelected(groupIndex, index)) selectedElement = el }">
|
||||
<FileIcon />
|
||||
{{ truncateContent(item.content) }}
|
||||
<img v-if="isUrl(item.content)" :src="getFavicon(item.content)" alt="Favicon" class="favicon">
|
||||
<FileIcon v-else />
|
||||
<img v-if="item.type === 'image'" :src="item.content" alt="Image" class="preview-image">
|
||||
<span v-else>{{ truncateContent(item.content) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</OverlayScrollbarsComponent>
|
||||
<OverlayScrollbarsComponent class="content">
|
||||
{{ selectedItem?.content || '' }}
|
||||
<img v-if="selectedItem?.type === 'image'" :src="selectedItem.content" alt="Image" class="full-image">
|
||||
<img v-else-if="isYoutubeWatchUrl(selectedItem?.content)" :src="getYoutubeThumbnail(selectedItem.content)" alt="YouTube Thumbnail" class="full-image">
|
||||
<span v-else>{{ selectedItem?.content || '' }}</span>
|
||||
</OverlayScrollbarsComponent>
|
||||
<Noise />
|
||||
</div>
|
||||
|
@ -47,7 +51,6 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, watch, nextTick } from 'vue';
|
||||
import Database from '@tauri-apps/plugin-sql';
|
||||
import { register, unregister, isRegistered } from '@tauri-apps/plugin-global-shortcut';
|
||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
|
@ -64,6 +67,7 @@ const selectedGroupIndex = ref(0);
|
|||
const selectedItemIndex = ref(0);
|
||||
const resultsContainer = ref(null);
|
||||
const selectedElement = ref(null);
|
||||
const searchInput = ref(null);
|
||||
const os = platform();
|
||||
|
||||
const groupedHistory = computed(() => {
|
||||
|
@ -172,6 +176,35 @@ const truncateContent = (content) => {
|
|||
return content.length > maxChars ? content.slice(0, maxChars - 3) + '...' : content;
|
||||
};
|
||||
|
||||
const isUrl = (str) => {
|
||||
const urlPattern = /^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
||||
return urlPattern.test(str);
|
||||
};
|
||||
|
||||
const isYoutubeWatchUrl = (url) => {
|
||||
return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/watch\?v=[\w-]+/.test(url);
|
||||
};
|
||||
|
||||
const getYoutubeThumbnail = (url) => {
|
||||
const videoId = url.match(/[?&]v=([^&]+)/)[1];
|
||||
return `https://img.youtube.com/vi/${videoId}/0.jpg`;
|
||||
};
|
||||
|
||||
const getFavicon = (url) => {
|
||||
const domain = url.replace(/^(https?:\/\/)?(www\.)?/, '').split('/')[0];
|
||||
return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`;
|
||||
};
|
||||
|
||||
const refreshHistory = async () => {
|
||||
const rawHistory = await db.value.select('SELECT * FROM history ORDER BY timestamp DESC');
|
||||
history.value = rawHistory.map(item => {
|
||||
if (item.type === 'image' && !item.content.startsWith('data:image')) {
|
||||
return { ...item, content: `data:image/png;base64,${item.content}` };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
db.value = await Database.load('sqlite:data.db');
|
||||
await refreshHistory();
|
||||
|
@ -181,12 +214,10 @@ onMounted(async () => {
|
|||
}
|
||||
|
||||
await listen('tauri://blur', hideApp);
|
||||
await listen('tauri://focus', focusSearchInput);
|
||||
focusSearchInput();
|
||||
});
|
||||
|
||||
const refreshHistory = async () => {
|
||||
history.value = await db.value.select('SELECT * FROM history ORDER BY timestamp DESC');
|
||||
};
|
||||
|
||||
const hideApp = async () => {
|
||||
await app.hide();
|
||||
await window.getCurrent().hide();
|
||||
|
@ -198,6 +229,13 @@ const showApp = async () => {
|
|||
await window.getCurrent().show();
|
||||
selectedGroupIndex.value = 0;
|
||||
selectedItemIndex.value = 0;
|
||||
focusSearchInput();
|
||||
};
|
||||
|
||||
const focusSearchInput = () => {
|
||||
nextTick(() => {
|
||||
searchInput.value?.focus();
|
||||
});
|
||||
};
|
||||
|
||||
const scrollToSelectedItem = () => {
|
||||
|
|
|
@ -52,6 +52,10 @@ body,
|
|||
background-color: transparent;
|
||||
}
|
||||
|
||||
.os-scrollbar-horizontal{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bg {
|
||||
width: 750px;
|
||||
height: 474px;
|
||||
|
@ -120,15 +124,19 @@ body,
|
|||
padding-bottom: 8px;
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.favicon{
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 53px;
|
||||
left: 284px;
|
||||
padding: 10px;
|
||||
padding: 8px;
|
||||
height: calc(100vh - 96px);
|
||||
padding-inline: 14px;
|
||||
font-family: SFMonoRegular !important;
|
||||
font-size: 12px;
|
||||
border-radius: 10px;
|
||||
|
@ -140,6 +148,13 @@ body,
|
|||
border-radius: 10px;
|
||||
font-family: SFMonoRegular !important;
|
||||
}
|
||||
|
||||
.full-image{
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue