From 1756aadaff0090c673e9b355079b72c2323a4570 Mon Sep 17 00:00:00 2001 From: Julio Ruiz Date: Tue, 26 May 2026 12:48:06 -0500 Subject: [PATCH] UI Fixes Adding page component to document results Adding aside to handle notes and highlights in future --- app/components/PublicationDetail.vue | 205 +++++++------ app/components/searchPanel/SearchPanel.vue | 2 - app/utils/itemUtilities.ts | 328 +++++++++++---------- app/utils/textUtilities.ts | 17 +- 4 files changed, 309 insertions(+), 243 deletions(-) diff --git a/app/components/PublicationDetail.vue b/app/components/PublicationDetail.vue index d21e4db..eb5382e 100644 --- a/app/components/PublicationDetail.vue +++ b/app/components/PublicationDetail.vue @@ -755,29 +755,35 @@ function highlightTextNodes(root: HTMLElement, terms: string[]): number { return matches.length } const isPopOverOpen = ref(false) -const anchor = ref({ x: 0, y: 0 }) -const virtualElement = computed(() => ({ - getBoundingClientRect: () => - ({ - width: 0, - height: 0, - left: anchor.value.x, - right: anchor.value.x, - top: anchor.value.y, - bottom: anchor.value.y, - ...anchor.value - } as DOMRect) -})) function handleSelection(event: MouseEvent) { const selection = window.getSelection() - if (selection && selection.toString().length > 0) { - anchor.value = { x: event.clientX, y: event.clientY } + if (selection && selection.toString().length > 3) { isPopOverOpen.value = true } else { isPopOverOpen.value = false } } + +const links = computed(() => { + return [ + { + label: 'Ver en sitio', + icon: 'ph-arrow-square-out', + to: matchUrl, + target: '_blank' + } + ] +}) + +const items = computed(() => { + return [ + { + label: 'Debug', + content: debugDocument(props.document) + } + ] +}) diff --git a/app/components/searchPanel/SearchPanel.vue b/app/components/searchPanel/SearchPanel.vue index 8133b52..53cfe9b 100644 --- a/app/components/searchPanel/SearchPanel.vue +++ b/app/components/searchPanel/SearchPanel.vue @@ -432,7 +432,6 @@ async function fetchDocumentWithParagraphs(docId: string) { selectedDocument.value = null selectedParagraphs.value = [] try { - console.log(`[fetchDocumentWithParagraphs] Fetching document with paragraphs. collection=${props.mainCollection} docId=${docId}`) const res = await documentsApi.multiSearch({ multiSearchParameters: {}, multiSearchSearchesParameter: { @@ -445,7 +444,6 @@ async function fetchDocumentWithParagraphs(docId: string) { }] } }) - console.log(`[fetchDocumentWithParagraphs] collection=${props.mainCollection} docId=${docId}`, JSON.stringify(res?.results?.[0], null, 2)) const hit = (res?.results?.[0] as { hits?: Array<{ document: Record }> })?.hits?.[0] if (hit) { const docRaw = { ...hit.document } diff --git a/app/utils/itemUtilities.ts b/app/utils/itemUtilities.ts index 1e69e3b..0bbef75 100755 --- a/app/utils/itemUtilities.ts +++ b/app/utils/itemUtilities.ts @@ -1,171 +1,199 @@ import dayjs from "dayjs"; export interface ItemObject { - id: string; - date: number; - slug: string; - type: string; - place: string; - city: string; - state: string; - country: string; - thumbnail: string; + id: string; + date: number; + slug: string; + type: string; + place: string; + city: string; + state: string; + country: string; + thumbnail: string; } export interface FilesObject { - youtube?: string; - video?: string; - audio?: string; - booklet?: string; - simple?: string; + youtube?: string; + video?: string; + audio?: string; + booklet?: string; + simple?: string; } -export function formatFiles( files:FilesObject ){ - const { $i18n } = useNuxtApp(); - const t = $i18n.t; +export function formatFiles(files: FilesObject) { + const { $i18n } = useNuxtApp(); + const t = $i18n.t; - let items = [] - if (files) { - if (files.youtube) { - items.push({ - to: files.youtube, - target: '_blank', - label: 'Youtube', - icon: 'ph:youtube-logo-thin', - labelClass: 'text-xs', - }) - } - if (files.video) { - items.push({ - to: files.video, - target: '_blank', - label: t('Activities.video'), - icon: 'ph:file-video-thin', - labelClass: 'text-xs' - }) - } - if (files.audio) { - items.push({ - to: `https://actividadeswp.carpa.com/wp-content/uploads/${files.audio}`, - target: '_blank', - label: t('Activities.audio'), - icon: 'ph:file-audio-thin', - labelClass: 'text-xs' - }) - } - if (files.booklet) { - items.push({ - to: files.booklet, - target: '_blank', - label: t('Activities.book'), - icon: 'ph:notebook-thin', - labelClass: 'text-xs' - }) - } - if (files.simple) { - items.push({ - to: files.simple, - target: '_blank', - label: t('Activities.simple'), - icon: 'ph:note-thin', - labelClass: 'text-xs' - }) - } + let items = []; + if (files) { + if (files.youtube) { + items.push({ + to: files.youtube, + target: "_blank", + label: "Youtube", + icon: "ph:youtube-logo-thin", + labelClass: "text-xs", + }); } - return items -} - -export function formatDate( d:number ){ - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - - let date = new Date(d * 1000) - - let dateString = date.toLocaleString(locale.value, { year: 'numeric', month:'long', day: 'numeric', weekday:'long', timeZone:'UTC' }) - return capitalizeFirstLetter( dateString ); -} - -export function formatLocation( i: ItemObject){ - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - const regionNames = new Intl.DisplayNames( - [ locale.value], {type: 'region'} - ); - - var locationParts = []; - locationParts.push(i?.place); - locationParts.push(i?.city); - locationParts.push(i?.state); - if( i.country ){ - locationParts.push(regionNames.of(i.country)); + if (files.video) { + items.push({ + to: files.video, + target: "_blank", + label: t("Activities.video"), + icon: "ph:file-video-thin", + labelClass: "text-xs", + }); } - - return locationParts.filter(Boolean).join(', '); -} - -export function getDay( d:number ){ - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - let date = new Date(d * 1000); - - return date.toLocaleString(locale.value, { weekday: 'long', timeZone: 'utc' }); -} - -export function getDayDate( d:number ){ - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - let date = new Date(d * 1000); - - return date.toLocaleString(locale.value, { day: 'numeric', timeZone: 'utc' }); -} - -export function getMonth( d:number ){ - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - let date = new Date(d * 1000); - - return date.toLocaleString(locale.value, { month: 'long', timeZone: 'utc' }); -} - -export function setUrl( item:ItemObject, isSearch:boolean ) { - const { $i18n } = useNuxtApp(); - const locale = $i18n.locale; - const date = dayjs(item.date*1000); - const month = (date.month()+1).toString() - const slug = (item.slug || item.slug === 'undefined' ? item.slug : item.id); - - if( isSearch ){ - return false; - } else { - return `/${locale.value}/${item.type}/${date.year()}/${month.padStart(2, '0')}/${slug}`; + if (files.audio) { + items.push({ + to: `https://actividadeswp.carpa.com/wp-content/uploads/${files.audio}`, + target: "_blank", + label: t("Activities.audio"), + icon: "ph:file-audio-thin", + labelClass: "text-xs", + }); } + if (files.booklet) { + items.push({ + to: files.booklet, + target: "_blank", + label: t("Activities.book"), + icon: "ph:notebook-thin", + labelClass: "text-xs", + }); + } + if (files.simple) { + items.push({ + to: files.simple, + target: "_blank", + label: t("Activities.simple"), + icon: "ph:note-thin", + labelClass: "text-xs", + }); + } + } + return items; } -export function getThumbnail( item:ItemObject ) { - console.log("ITEM",item); - let path = item.thumbnail - if (!path) { - return "https://images.carpa.com/tr:w-900,f-auto/youtube_thumbnail_46396.png" +export function formatDate(d: number) { + if (!d) { + return + } + + const { $i18n } = useNuxtApp() + const locale = $i18n.locale + + const date = new Date(d * 1000) + + const dateString = date.toLocaleString(locale.value, { + year: 'numeric', + month: 'long', + day: 'numeric', + weekday: 'long', + timeZone: 'UTC' + }) + return capitalizeFirstLetter(dateString) +} + +export function formatLocation(i: ItemObject) { + if (!i) { + return + } + const { $i18n } = useNuxtApp() + const locale = $i18n.locale + const regionNames = new Intl.DisplayNames([locale.value], { type: 'region' }) + + const locationParts = [] + locationParts.push(i?.place) + locationParts.push(i?.city) + locationParts.push(i?.state) + if (i.country) { + locationParts.push(regionNames.of(i.country)) + } + + return locationParts.filter(Boolean).join(', ') +} + +export function formatSignature(i: ItemObject) { + const date = formatDate(i?.timestamp) + const location = formatLocation(i) + if (date === undefined || location === undefined) { + return + } + const val = `${date} - ${location}` + + if (!val) { + return + } + return val +} + +export function getDay(d: number) { + const { $i18n } = useNuxtApp(); + const locale = $i18n.locale; + let date = new Date(d * 1000); + + return date.toLocaleString(locale.value, { + weekday: "long", + timeZone: "utc", + }); +} + +export function getDayDate(d: number) { + const { $i18n } = useNuxtApp(); + const locale = $i18n.locale; + let date = new Date(d * 1000); + + return date.toLocaleString(locale.value, { day: "numeric", timeZone: "utc" }); +} + +export function getMonth(d: number) { + const { $i18n } = useNuxtApp(); + const locale = $i18n.locale; + let date = new Date(d * 1000); + + return date.toLocaleString(locale.value, { month: "long", timeZone: "utc" }); +} + +export function setUrl(item: ItemObject, isSearch: boolean) { + const { $i18n } = useNuxtApp(); + const locale = $i18n.locale; + const date = dayjs(item.date * 1000); + const month = (date.month() + 1).toString(); + const slug = item.slug || item.slug === "undefined" ? item.slug : item.id; + + if (isSearch) { + return false; } else { - return `https://images.carpa.com/${item.type}/${path}?tr=w-900` + return `/${locale.value}/${item.type}/${date.year()}/${month.padStart(2, "0")}/${slug}`; } } -export function getAuthor( type:string ){ - let author = '' - switch (type){ - case "activities": - author = 'Dr. José Benjamín Pérez Matos' - break - case "conferences": - author = 'Dr. William Soto Santiago' - break - case "sermons": - author = 'William Marrion Branham'; - break - } - return author +export function getThumbnail(item: ItemObject) { + console.log("ITEM", item); + let path = item.thumbnail; + if (!path) { + return "https://images.carpa.com/tr:w-900,f-auto/youtube_thumbnail_46396.png"; + } else { + return `https://images.carpa.com/${item.type}/${path}?tr=w-900`; + } +} + +export function getAuthor(type: string) { + let author = ""; + switch (type) { + case "activities": + author = "Dr. José Benjamín Pérez Matos"; + break; + case "conferences": + author = "Dr. William Soto Santiago"; + break; + case "sermons": + author = "William Marrion Branham"; + break; + } + return author; } // removed: openItem relied on a Pinia store that is not installed in this app. -// Detail navigation is now handled directly inside the search pages. \ No newline at end of file +// Detail navigation is now handled directly inside the search pages. diff --git a/app/utils/textUtilities.ts b/app/utils/textUtilities.ts index fd96da8..013face 100644 --- a/app/utils/textUtilities.ts +++ b/app/utils/textUtilities.ts @@ -1,5 +1,5 @@ /* Copy to Clipboard */ -export async function copyToClipboard(textToCopy: string, type: string) { +export async function copyToClipboard(type: string) { const toast = useToast() const selection = window.getSelection() @@ -29,3 +29,18 @@ export async function copyToClipboard(textToCopy: string, type: string) { console.error('Failed to copy: ', err) } } + +export function debugDocument(json) { + let data = '' + // Iterate through keys and values + for (const key in json) { + if (json.hasOwnProperty(key)) { + data += `${key}: ${json[key]}\n\r` + } + } + return data +} + +export function addNote() { + return 'yay' +}