Work on search

This commit is contained in:
mustafa-rezae 2025-04-22 15:55:38 +03:30
parent 2cff09d0a0
commit 0db2ba3f38
4 changed files with 88 additions and 341 deletions

View File

@ -75,67 +75,57 @@ const removeFromFavorites = async (item = {}, index = 0) => {
</script> </script>
<template> <template>
<div class="search-list firefox-scrollbar"> <div
<div v-if="props?.list?.length"
v-if="props?.list?.length" class="search-list-item"
class="search-list-item" v-for="(item, index) in props.list"
v-for="(item, index) in props.list" :key="index"
:key="index" >
<div class="flex justify-between mt-4 mb-2">
<a
:href="`/haditha/search/${item?._source?.id}/${
item?._source?.meta?.hadith_masoum ??
item?._source?.meta?.hadith_sanad
}`"
@click.prevent="openModal(item)"
class="from-person block"
> >
<div class="flex justify-between mt-4 mb-2"> {{
<a item?._source?.meta?.hadith_masoum ??
:href="`/haditha/search/${item?._source?.id}/${ item?._source?.meta?.hadith_sanad
item?._source?.meta?.hadith_masoum ?? }}
item?._source?.meta?.hadith_sanad </a>
}`" <UButton
@click.prevent="openModal(item)" v-if="route.name == 'hadithaFavorites'"
class="from-person block" @click="removeFromFavorites(item)"
> variant="ghost"
{{ color="error"
item?._source?.meta?.hadith_masoum ?? class="copy-btn"
item?._source?.meta?.hadith_sanad label="حذف"
}} />
</a>
<UButton
v-if="route.name == 'hadithaFavorites'"
@click="removeFromFavorites(item)"
variant="ghost"
color="error"
class="copy-btn"
label="حذف"
/>
</div>
<a
@click.prevent="openModal(item)"
class="arabic-text block"
:href="`/haditha/search/${item?._source?.id}/${item?._source?.content_ar}`"
>
{{ item?._source?.content_ar }}
</a>
<a
@click.prevent="openModal(item)"
:href="`/haditha/search/${item?._source?.id}/${item?._source?.content}`"
class="persian-text block"
v-html="item?.highlight?.['content.fa'] ?? item?._source?.content"
></a>
<div class="flex justify-end">
<p class="reference">
{{ item?._source?.address?.vol_title }}، صفحه
{{ item?._source?.address?.page_num }}
</p>
</div>
</div>
<no-data
class="h-full w-full flex flex-col justify-center items-center"
v-else
>
<img fit="auto" quality="80" placeholder :src="props.noDataIcon" />
<p class="no-data-text">{{ props.noDataText }}</p>
</no-data>
</div> </div>
<a
@click.prevent="openModal(item)"
class="arabic-text block"
:href="`/haditha/search/${item?._source?.id}/${item?._source?.content_ar}`"
>
{{ item?._source?.content_ar }}
</a>
<a
@click.prevent="openModal(item)"
:href="`/haditha/search/${item?._source?.id}/${item?._source?.content}`"
class="persian-text block"
v-html="item?.highlight?.['content.fa'] ?? item?._source?.content"
></a>
<div class="flex justify-end">
<p class="reference">
{{ item?._source?.address?.vol_title }}، صفحه
{{ item?._source?.address?.page_num }}
</p>
</div>
</div>
<!-- <UModal <!-- <UModal
v-model:open="isModalOpen" v-model:open="isModalOpen"
:dismissible="false" :dismissible="false"
@ -189,77 +179,11 @@ const removeFromFavorites = async (item = {}, index = 0) => {
color: var(--ui-color-two); color: var(--ui-color-two);
margin-bottom: 0.5em; margin-bottom: 0.5em;
.search-list-item { &:hover,
.from-person { &:focus,
font-family: IRANSansX; &:active {
font-weight: 300; cursor: pointer;
font-size: 0.75rem; /*12px*/ background-color: #fafafa;
line-height: 1.125rem; /*18px*/
letter-spacing: 0%;
text-align: right;
color: #00a762; /* #4be8ae 7.38% */
margin-bottom: 0.5em;
&:hover,
&:focus,
&:active {
cursor: pointer;
background-color: #fafafa;
}
}
.arabic-text {
font-family: Takrim;
font-weight: 400;
font-size: 1.125rem; /*18px*/
line-height: 2rem; /*23px*/
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
margin-bottom: 0.5em;
&:hover,
&:focus,
&:active {
cursor: pointer;
background-color: #fafafa;
}
}
.persian-text {
font-family: Takrim;
font-weight: 400;
font-size: 1rem; /*16px*/
line-height: 1.375rem; /*22px*/
letter-spacing: 0%;
text-align: right;
color: #626b84;
margin-bottom: 0.5em;
}
.reference {
height: 24px;
gap: 4px;
padding-top: 0.25em; /*4px*/
padding-right: 0.5em; /*8px*/
padding-bottom: 0.25em; /*4px*/
padding-left: 0.5em; /*8px*/
border-radius: 6px; /*18px*/
border-width: 0.5px;
border: 0.5px solid #d9d9d9;
font-family: IRANSansX;
font-weight: 300;
font-size: 0.625rem; /*10px*/
line-height: 0.9rem; /*15px*/
letter-spacing: 0%;
text-align: right;
color: #8a92a8;
&:hover,
&:focus,
&:active {
cursor: pointer;
background-color: #fafafa;
}
}
} }
} }
.persian-text { .persian-text {
@ -285,8 +209,8 @@ const removeFromFavorites = async (item = {}, index = 0) => {
font-family: IRANSansX; font-family: IRANSansX;
font-weight: 300; font-weight: 300;
font-size: 1rem; font-size: 0.625rem; /*10px*/
line-height: 1.5rem; /*24px*/ line-height: 0.9rem; /*15px*/
letter-spacing: 0%; letter-spacing: 0%;
text-align: right; text-align: right;
color: #8a92a8; color: #8a92a8;
@ -300,103 +224,3 @@ const removeFromFavorites = async (item = {}, index = 0) => {
} }
} }
</style> </style>
<!--
<style>
.text__orange {
color: orange;
}
.modal-content {
border: 0.3px solid #e0e0e0;
box-shadow: 0px 8px 20px 0px #0000001a;
background: #ffffff;
width: 100%;
max-width: 720px; /*18px*/
border-radius: 16px; /*18px*/
gap: 8px;
border-width: 0.3px;
.modal-body {
border-radius: 16px; /*18px*/
height: 800px; /*18px*/
position: relative;
.top-left-bgi {
position: absolute;
top: 0;
left: 0;
background-image: url("../../../assets/haditha/images/modal-top-bgi.png");
backdrop-filter: blur(54px);
width: 447px;
height: 447px;
top: 0;
left: 0;
background-repeat: no-repeat;
background-size: auto;
z-index: -1;
}
&::before {
content: "";
position: absolute;
right: 0;
bottom: 0;
background-image: url("../../../assets/haditha/images/modal-bttom-right-bgi.png");
backdrop-filter: blur(54px);
width: 438px;
height: 238px;
mix-blend-mode: Multiply;
background-repeat: no-repeat;
background-size: cover;
z-index: -1;
}
&::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 458px;
height: 239px;
mix-blend-mode: Multiply;
background-image: url("../../../assets/haditha/images/modal-bottom-left-bgi.png");
background-repeat: no-repeat;
background-size: cover;
backdrop-filter: blur(54px);
z-index: -1;
}
}
}
.modal-overlay {
background: #00000033;
}
.copy-btn {
padding: 0.2em 1em;
/* width: 44px; */
/* height: 24px; */
gap: 4px;
border-radius: 6px;
border-width: 0.5px;
padding-top: 4px;
padding-right: 12px;
padding-bottom: 4px;
padding-left: 12px;
/* background: #ffffff; */
/* border: 0.5px solid #d9d9d9; */
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 18px;
letter-spacing: 0%;
text-align: right;
/* color: #a71111; */
}
</style>

View File

@ -199,7 +199,7 @@ const onClose = () => {
const handlePagination = ( const handlePagination = (
prevNextIndicator: number, prevNextIndicator: number,
pageNumber: number | undefined = undefined userEnteredPage: number | undefined = undefined
) => { ) => {
if (loading.value) return; if (loading.value) return;
loading.value = true; loading.value = true;
@ -215,10 +215,14 @@ const handlePagination = (
let url = repoUrl() + hadithaApi.library.prevNextHadith; let url = repoUrl() + hadithaApi.library.prevNextHadith;
url = url.replace("@index_key", "dhparag"); url = url.replace("@index_key", "dhparag");
url = url.replace("@vol_id", volId); url = url.replace("@vol_id", volId);
url = url.replace("@page_num", (pageNumber ?? page_num.value).toString()); url = url.replace(
"@page_num",
(userEnteredPage ?? page_num.value).toString()
);
url = url.replace("@step", prevNextIndicator.toString()); url = url.replace("@step", prevNextIndicator.toString());
page_num.value += prevNextIndicator; // اگر کاربر شماره صفحه ای را وارد نکرده باشد..
if (!userEnteredPage) page_num.value = +page_num.value + prevNextIndicator;
httpService httpService
.getRequest(url) .getRequest(url)
@ -248,11 +252,13 @@ const getDataTree = () => {
const prepareTreeData = (data) => { const prepareTreeData = (data) => {
return data.map((item) => { return data.map((item) => {
return { const res = {
...item, ...item,
...item._source, ...item._source,
title: item._source.content, title: item._source.content,
}; };
delete res._source;
return res;
}); });
}; };
@ -320,7 +326,7 @@ const UTree = defineAsyncComponent(
</div> </div>
<div class="separator"></div> <div class="separator"></div>
<div class="page-content py-14 p-2"> <div class="page-content firefox-scrollbar py-14 p-2">
<!-- <h2></h2> --> <!-- <h2></h2> -->
<p <p
v-if="state.selectedItem?.length" v-if="state.selectedItem?.length"

View File

@ -12,6 +12,8 @@
import hadithaApi from "@haditha/apis/hadithaApi"; import hadithaApi from "@haditha/apis/hadithaApi";
import type { HadithResponseModel } from "@haditha/types/hadithType"; import type { HadithResponseModel } from "@haditha/types/hadithType";
import type { HadithResponseShowModel } from "~/systems/hadith_ui/types/hadithType"; import type { HadithResponseShowModel } from "~/systems/hadith_ui/types/hadithType";
import headLinks from "@haditha/json/haditha/headLinks";
import headMetas from "@haditha/json/haditha/headMetas";
// #endregion imports // #endregion imports
// #region meta // #region meta
@ -24,94 +26,12 @@ useHead({
title: `${import.meta.env.VITE_HADITH_PAGE_TITLE}`, title: `${import.meta.env.VITE_HADITH_PAGE_TITLE}`,
meta: [ meta: [
{ name: "description", content: "کاوش با هوش مصنوعی در احادیث اسلامی" }, { name: "description", content: "کاوش با هوش مصنوعی در احادیث اسلامی" },
{ ...headMetas,
name: "msapplication-TileImage",
content: "/img/haditha/fav-icons/ms-icon-144x144.png",
},
{ name: "theme-color", content: "#ffffff" },
], ],
bodyAttrs: { bodyAttrs: {
class: import.meta.env.VITE_HADITH_SYSTEM, class: import.meta.env.VITE_HADITH_SYSTEM,
}, },
link: [ link: headLinks,
{
rel: "icon",
type: "image/x-icon",
href: "/img/haditha/fav-icons/favicon.ico",
},
{ rel: "manifest", href: "/img/haditha/fav-icons/manifest.json" },
// rel: icon
{
rel: "icon",
type: "image/png",
sizes: "16x16",
href: "/img/haditha/fav-icons/favicon-16x16.png",
},
{
rel: "icon",
type: "image/png",
sizes: "32x32",
href: "/img/haditha/fav-icons/favicon-32x32.png",
},
{
rel: "icon",
type: "image/png",
sizes: "96x96",
href: "/img/haditha/fav-icons/favicon-96x96.png",
},
{
rel: "icon",
sizes: "192x192",
type: "image/png",
href: "/img/haditha/fav-icons/android-icon-192x192.png",
},
// rel: apple
{
rel: "apple-touch-icon",
sizes: "57x57",
href: "/img/haditha/fav-icons/apple-icon-57x57.png",
},
{
rel: "apple-touch-icon",
sizes: "60x60",
href: "/img/haditha/fav-icons/android-icon-60x60.png",
},
{
rel: "apple-touch-icon",
sizes: "72x72",
href: "/img/haditha/fav-icons/android-icon-72x72.png",
},
{
rel: "apple-touch-icon",
sizes: "76x76",
href: "/img/haditha/fav-icons/android-icon-76x76.png",
},
{
rel: "apple-touch-icon",
sizes: "114x114",
href: "/img/haditha/fav-icons/android-icon-114x114.png",
},
{
rel: "apple-touch-icon",
sizes: "120x120",
href: "/img/haditha/fav-icons/android-icon-120x120.png",
},
{
rel: "apple-touch-icon",
sizes: "144x144",
href: "/img/haditha/fav-icons/android-icon-144x144.png",
},
{
rel: "apple-touch-icon",
sizes: "152x152",
href: "/img/haditha/fav-icons/android-icon-152x152.png",
},
{
rel: "apple-touch-icon",
sizes: "180x180",
href: "/img/haditha/fav-icons/android-icon-180x180.png",
},
],
}); });
// #endregion imports // #endregion imports
@ -335,7 +255,7 @@ const handlePagination = (prevNextIndicator: string) => {
</div> </div>
</div> </div>
<div class="content"> <div class="content firefox-scrollbar">
<div class="search-item"> <div class="search-item">
<div class="text-arabic-section"> <div class="text-arabic-section">
<div class="section-header"> <div class="section-header">
@ -513,11 +433,10 @@ const handlePagination = (prevNextIndicator: string) => {
<!-- because of the buttons, using without scoped. --> <!-- because of the buttons, using without scoped. -->
<style> <style>
.page-inner-container{ .page-inner-container {
height: 100%; height: 100%;
} }
.search-show-page { .search-show-page {
.body-header { .body-header {
.modal-title { .modal-title {
padding: 0 0.5em 1.5em; padding: 0 0.5em 1.5em;
@ -846,7 +765,7 @@ const handlePagination = (prevNextIndicator: string) => {
.body-content { .body-content {
.content { .content {
height: calc(100dvh - 15em); height: calc(100dvh - 15em);
overflow-y: auto; overflow-y: auto;
} }
} }
} }

View File

@ -13,6 +13,7 @@ import type { Synonym } from "@haditha/types/hadithType";
// const searchTerm = useState("searchTerm", () => ''); // Tracks the searchTerm // const searchTerm = useState("searchTerm", () => ''); // Tracks the searchTerm
const offset = useState("offset", () => 0); // Tracks the current offset const offset = useState("offset", () => 0); // Tracks the current offset
const total = useState("total", () => 0); // Tracks the total
definePageMeta({ definePageMeta({
layout: false, layout: false,
@ -48,15 +49,13 @@ const httpService = useNuxtApp()["$http"];
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
// تعداد کل نتایج // تعداد کل نتایج
const total = ref(0);
// رکوردهای جتسجو شده توسط کاربر // رکوردهای جتسجو شده توسط کاربر
const userSearchHistory = useStorage( const userSearchHistory = useStorage(
"userSearchHistory", "userSearchHistory",
new Set() // Initial value new Set() // Initial value
); );
// کلمه ی جستجو شده توسط کاربر // کلمه ی جستجو شده توسط کاربر
const searchTerm = ref(route.query.q ?? ""); const searchTerm = ref<string>(<string>route.query.q ?? "");
// وقتی کاربر از صفحه اصلی وارد جستجو میشود. // وقتی کاربر از صفحه اصلی وارد جستجو میشود.
// if (route.query.q) { // if (route.query.q) {
// searchTerm.value = route.query.q ?? ""; // searchTerm.value = route.query.q ?? "";
@ -220,10 +219,15 @@ const sendQuery = async (payload = {}) => {
: "q=none" : "q=none"
); );
// fetch search list from backend(ssr)
return await httpService.postRequest(url, payload).then((res) => { return await httpService.postRequest(url, payload).then((res) => {
total.value = res.hits.total.value ?? 0; total.value = res.hits.total.value ?? 0;
offset.value += mainState.pagination.limit; offset.value += mainState.pagination.limit;
// check if search term is not empty
if (searchTerm.value) userSearchHistory.value.add(searchTerm.value); // Add the value to the Set
// close the history dropdown menu
open.value = false;
return res; return res;
}); });
}; };
@ -236,14 +240,15 @@ const { data: loadedItems } = await useAsyncData("search", () => sendQuery(), {
}, },
}); });
const onBeforeSendQuery = () => { const onBeforeSendQuery = (from) => {
route.query.q = searchTerm.value;
history?.pushState( history?.pushState(
{}, {},
document?.title, document?.title,
route.path + `?q=${searchTerm.value}` route.path + `?q=${searchTerm.value}`
); );
offset.value = 0;
sendQuery().then((res) => { sendQuery().then((res) => {
loadedItems.value = res.hits.hits; loadedItems.value = res.hits.hits;
}); });
@ -261,14 +266,7 @@ useInfiniteScroll(
const hits = res.hits.hits; const hits = res.hits.hits;
if (hits.length) { if (hits.length) {
// if (initialItems.value.length) {
// loadedItems.value.push(...initialItems.value);
// loadedItems.value.push(...hits);
// initialItems.value = [];
// } else loadedItems.value.push(...hits);
loadedItems.value.push(...hits); loadedItems.value.push(...hits);
offset.value += mainState.pagination.limit;
} else { } else {
hasMore.value = false; hasMore.value = false;
} }
@ -491,8 +489,8 @@ const SearchList = defineAsyncComponent(
highlightOnHover highlightOnHover
@focus="open = true" @focus="open = true"
@blur="open = false" @blur="open = false"
@change="onBeforeSendQuery" @change="onBeforeSendQuery('change')"
@keydown.enter="onBeforeSendQuery" @keydown.enter="onBeforeSendQuery('enter')"
> >
<!-- @keydown="onKeyDown" --> <!-- @keydown="onKeyDown" -->
<!-- @update:modelValue="onUpdateModel" --> <!-- @update:modelValue="onUpdateModel" -->
@ -739,7 +737,7 @@ const SearchList = defineAsyncComponent(
</div> </div>
</div> </div>
<div <div
v-if="searchTerm?.length == 0" v-if="searchTerm?.length == 0 && loadedItems?.length == 0"
class="flex justify-center flex-col items-center mt-10" class="flex justify-center flex-col items-center mt-10"
> >
<img <img
@ -756,7 +754,7 @@ const SearchList = defineAsyncComponent(
</div> </div>
<div <div
v-if="loadedItems.length" v-else-if="searchTerm?.length && loadedItems?.length"
class="search-box-container pb-0 bg-white flex justify-center" class="search-box-container pb-0 bg-white flex justify-center"
> >
<div class="search-list-contianer"> <div class="search-list-contianer">