diff --git a/pages/index.vue b/pages/index.vue index 0426d08..9c5b52e 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -129,130 +129,10 @@ class="information" :options="{ scrollbars: { autoHide: 'scroll' } }">
Information
-
- -
-

Source

- {{ selectedItem.source }} -
-
-

Content Type

- {{ - selectedItem.content_type.charAt(0).toUpperCase() + - selectedItem.content_type.slice(1) - }} -
- - - - - - - - - - - - - - - - - - - - -
-

Copied

- {{ getFormattedDate }} +
+
+

{{ row.label }}

+ {{ row.value }}
@@ -269,7 +149,9 @@ import { platform } from "@tauri-apps/plugin-os"; import { enable, isEnabled } from "@tauri-apps/plugin-autostart"; import { listen } from "@tauri-apps/api/event"; import { useNuxtApp } from "#app"; +import { invoke } from "@tauri-apps/api/core"; import { HistoryItem, ContentType } from "~/types/types"; +import type { InfoText, InfoImage, InfoFile, InfoLink, InfoColor, InfoCode } from "~/types/types"; interface GroupedHistory { label: string; @@ -299,6 +181,8 @@ const imageSizes = shallowRef>({}); const lastUpdateTime = ref(Date.now()); const imageLoadError = ref(false); const imageLoading = ref(false); +const pageTitle = ref(''); +const pageOgImage = ref(''); const keyboard = useKeyboard(); @@ -385,7 +269,9 @@ const loadHistoryChunk = async (): Promise => { item.source, item.content_type, item.content, - item.favicon + item.favicon, + item.source_icon, + item.language ); Object.assign(historyItem, { id: item.id, @@ -776,11 +662,6 @@ watch([selectedGroupIndex, selectedItemIndex], () => scrollToSelectedItem(false) ); -const getComputedImageUrl = (item: HistoryItem | null): string => { - if (!item) return ""; - return imageUrls.value[item.id] || ""; -}; - const getCharacterCount = computed(() => { return selectedItem.value?.content.length ?? 0; }); @@ -808,6 +689,164 @@ const formatFileSize = (bytes: number): string => { const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; + +const fetchPageMeta = async (url: string) => { + try { + console.log('Fetching metadata for:', url); + const [title, ogImage] = await invoke('fetch_page_meta', { url }) as [string, string | null]; + console.log('Received title:', title); + pageTitle.value = title; + if (ogImage) { + pageOgImage.value = ogImage; + } + } catch (error) { + console.error('Error fetching page meta:', error); + pageTitle.value = 'Error loading title'; + } +}; + +watch(() => selectedItem.value, (newItem) => { + if (newItem?.content_type === ContentType.Link) { + pageTitle.value = 'Loading...'; + pageOgImage.value = ''; + fetchPageMeta(newItem.content); + } else { + pageTitle.value = ''; + pageOgImage.value = ''; + } +}); + +const getInfo = computed(() => { + if (!selectedItem.value) return null; + + const baseInfo = { + source: selectedItem.value.source, + copied: selectedItem.value.timestamp, + }; + + const infoMap: Record InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode> = { + [ContentType.Text]: () => ({ + ...baseInfo, + content_type: ContentType.Text, + characters: selectedItem.value!.content.length, + words: selectedItem.value!.content.trim().split(/\s+/).length, + }), + [ContentType.Image]: () => ({ + ...baseInfo, + content_type: ContentType.Image, + dimensions: imageDimensions.value[selectedItem.value!.id] || "Loading...", + size: parseInt(imageSizes.value[selectedItem.value!.id] || "0"), + }), + [ContentType.File]: () => ({ + ...baseInfo, + content_type: ContentType.File, + path: selectedItem.value!.content, + filesize: 0, + }), + [ContentType.Link]: () => ({ + ...baseInfo, + content_type: ContentType.Link, + title: pageTitle.value, + url: selectedItem.value!.content, + characters: selectedItem.value!.content.length, + }), + [ContentType.Color]: () => { + const hex = selectedItem.value!.content; + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + + const rNorm = r / 255; + const gNorm = g / 255; + const bNorm = b / 255; + + const max = Math.max(rNorm, gNorm, bNorm); + const min = Math.min(rNorm, gNorm, bNorm); + let h = 0, s = 0; + const l = (max + min) / 2; + + if (max !== min) { + const d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case rNorm: + h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0); + break; + case gNorm: + h = (bNorm - rNorm) / d + 2; + break; + case bNorm: + h = (rNorm - gNorm) / d + 4; + break; + } + h /= 6; + } + + return { + ...baseInfo, + content_type: ContentType.Color, + hex: hex, + rgb: `rgb(${r}, ${g}, ${b})`, + hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`, + }; + }, + [ContentType.Code]: () => ({ + ...baseInfo, + content_type: ContentType.Code, + language: selectedItem.value!.language ?? "Unknown", + lines: selectedItem.value!.content.split('\n').length, + }), + }; + + return infoMap[selectedItem.value.content_type](); +}); + +const infoRows = computed(() => { + if (!getInfo.value) return []; + + const commonRows = [ + { label: "Source", value: getInfo.value.source }, + { label: "Content Type", value: getInfo.value.content_type.charAt(0).toUpperCase() + getInfo.value.content_type.slice(1) }, + ]; + + const typeSpecificRows: Record> = { + [ContentType.Text]: [ + { label: "Characters", value: (getInfo.value as InfoText).characters }, + { label: "Words", value: (getInfo.value as InfoText).words }, + ], + [ContentType.Image]: [ + { label: "Dimensions", value: (getInfo.value as InfoImage).dimensions }, + { label: "Image size", value: formatFileSize((getInfo.value as InfoImage).size) }, + ], + [ContentType.File]: [ + { label: "Path", value: (getInfo.value as InfoFile).path }, + ], + [ContentType.Link]: [ + { label: "Title", value: (getInfo.value as InfoLink).title || "No Title Found" }, + { label: "URL", value: (getInfo.value as InfoLink).url }, + { label: "Characters", value: (getInfo.value as InfoLink).characters }, + ], + [ContentType.Color]: [ + { label: "Hex Code", value: (getInfo.value as InfoColor).hex }, + { label: "RGB", value: (getInfo.value as InfoColor).rgb }, + { label: "HSL", value: (getInfo.value as InfoColor).hsl }, + ], + [ContentType.Code]: [ + { label: "Language", value: (getInfo.value as InfoCode).language }, + { label: "Lines", value: (getInfo.value as InfoCode).lines }, + ], + }; + + const specificRows = typeSpecificRows[getInfo.value.content_type] + .filter(row => row.value !== ""); + + return [ + ...commonRows, + ...specificRows, + { label: "Copied", value: getFormattedDate.value }, + ]; +});