Fix page refresh bug in library and search
This commit is contained in:
parent
dc2d5cc460
commit
917824f098
|
@ -31,7 +31,6 @@ const goToLibraryShow = (item) => {
|
|||
|
||||
<template>
|
||||
<UCard
|
||||
v-if="props.list?.length"
|
||||
v-for="(item, index) in props.list"
|
||||
class="mx-auto"
|
||||
:key="index"
|
||||
|
@ -46,7 +45,6 @@ const goToLibraryShow = (item) => {
|
|||
<!-- <template #header></template> -->
|
||||
|
||||
<ULink
|
||||
v-if="item?._source?.id"
|
||||
:to="{
|
||||
name: 'hadithaLibraryShow',
|
||||
params: {
|
||||
|
@ -65,8 +63,8 @@ const goToLibraryShow = (item) => {
|
|||
quality="80"
|
||||
placeholder
|
||||
src="/img/haditha/library/totally.webp"
|
||||
/>
|
||||
<!-- src="/img/haditha/sample-bgi.svg" -->
|
||||
/>
|
||||
<!-- src="/img/haditha/sample-bgi.svg" -->
|
||||
<p class="title">{{ item?._source?.title }}</p>
|
||||
<p class="version">
|
||||
جلد
|
||||
|
@ -76,14 +74,6 @@ const goToLibraryShow = (item) => {
|
|||
|
||||
<!-- <template #footer> </template> -->
|
||||
</UCard>
|
||||
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -7,6 +7,9 @@ const props = defineProps({
|
|||
return [];
|
||||
},
|
||||
},
|
||||
requestStatus: {
|
||||
default: "pending",
|
||||
},
|
||||
total: {
|
||||
default: 0,
|
||||
},
|
||||
|
@ -84,6 +87,17 @@ const removeFromFavorites = async (item = {}, index = 0) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <template v-if="props.requestStatus == 'pending'"> -->
|
||||
<!-- <div class="flex items-center gap-4 mb-4" v-for="item in props?.list?.length">
|
||||
<USkeleton class="h-12 w-12 rounded-full" />
|
||||
|
||||
<div class="grid gap-2 flex-grow-1">
|
||||
<USkeleton class="h-4 " />
|
||||
<USkeleton class="h-4 " />
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- </template> -->
|
||||
<!-- <template v-else-if="props.requestStatus == 'success' || props.requestStatus == 'idle'"> -->
|
||||
<div
|
||||
v-if="props?.list?.length"
|
||||
class="search-list-item"
|
||||
|
@ -155,6 +169,7 @@ const removeFromFavorites = async (item = {}, index = 0) => {
|
|||
</p> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- </template> -->
|
||||
|
||||
<!-- <UModal
|
||||
v-model:open="isModalOpen"
|
||||
|
|
|
@ -2,14 +2,22 @@
|
|||
import hadithaApi from "@haditha/apis/hadithaApi";
|
||||
import headLinks from "@haditha/json/haditha/headLinks";
|
||||
import headMetas from "@haditha/json/haditha/headMetas";
|
||||
import { useInfiniteScroll } from "@vueuse/core";
|
||||
// import { useInfiniteScroll } from "@vueuse/core";
|
||||
const id_token = useCookie("id_token");
|
||||
const token = id_token.value ?? "GuestAccess";
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const baseUrl =
|
||||
config.public.NUXT_PUBLIC_BASE_URL + config.public.NUXT_PUBLIC_API_NAME;
|
||||
|
||||
// this enable us to send cookies.
|
||||
const requestFetch = useRequestFetch();
|
||||
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
name: "hadithaLibrary",
|
||||
});
|
||||
useHead({
|
||||
name: "hadithaLibrary",
|
||||
title: `${import.meta.env.VITE_HADITH_PAGE_TITLE} | کتابخانه`,
|
||||
meta: [
|
||||
{ name: "description", content: "کاوش با هوش مصنوعی در احادیث اسلامی" },
|
||||
|
@ -22,19 +30,21 @@ useHead({
|
|||
});
|
||||
|
||||
// #region refs
|
||||
const httpService = useNuxtApp()["$http"];
|
||||
// const httpService = useNuxtApp()["$http"];
|
||||
// const { $api } = useNuxtApp()
|
||||
const offset = useState("offset", () => 0);
|
||||
const total = useState("total", () => 0);
|
||||
const loading = useState("loading", () => false);
|
||||
const hasMore = useState("hasMore", () => true);
|
||||
// const libraryList = useState("libraryList", () => []);
|
||||
// const loading = useState("loading", () => false);
|
||||
// const hasMore = useState("hasMore", () => true);
|
||||
|
||||
const el = ref(null);
|
||||
// const el = ref(null);
|
||||
// #endregion refs
|
||||
|
||||
// #region reactive
|
||||
const state = reactive({
|
||||
pagination: {
|
||||
limit: 10,
|
||||
limit: 15,
|
||||
page: 1,
|
||||
pages: 1,
|
||||
},
|
||||
|
@ -42,59 +52,65 @@ const state = reactive({
|
|||
|
||||
// #region methods
|
||||
|
||||
const getLibraryList = async () => {
|
||||
let url = repoUrl() + hadithaApi.library.list;
|
||||
const getLibraryList = () => {
|
||||
let url = baseUrl + repoUrl() + hadithaApi.library.list;
|
||||
url = url.replace("@field_collapsed", "normal");
|
||||
url = url.replace("@offset", offset.value);
|
||||
url = url.replace("@limit", state.pagination.limit);
|
||||
url = url.replace("@q", "none");
|
||||
|
||||
return await httpService.postRequest(url).then((res) => {
|
||||
total.value = res.hits?.total?.value ?? 0;
|
||||
return requestFetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: token,
|
||||
},
|
||||
}).then((data) => {
|
||||
total.value = data.hits?.total?.value ?? 0;
|
||||
offset.value += state.pagination.limit;
|
||||
|
||||
return res;
|
||||
return data.hits?.hits;
|
||||
});
|
||||
};
|
||||
|
||||
// Server-side initial load
|
||||
const { data: loadedItems } = await useAsyncData(
|
||||
"libraryList",
|
||||
() => getLibraryList(),
|
||||
{
|
||||
transform: (data) => data.hits.hits,
|
||||
}
|
||||
// Wrapping with useAsyncDataavoid double data fetching when
|
||||
// doing server-side rendering (server & client on hydration).
|
||||
const { data: libraryList } = await useAsyncData("libraryList", () =>
|
||||
getLibraryList()
|
||||
);
|
||||
|
||||
// Client-side infinite scroll
|
||||
useInfiniteScroll(
|
||||
el,
|
||||
async () => {
|
||||
if (!hasMore.value || loading.value) return;
|
||||
const loadMore = async () => {
|
||||
// const listElm = $event.target;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
await getLibraryList().then((res) => {
|
||||
const hits = res?.hits?.hits ?? [];
|
||||
// if (status.value == "pending") return;
|
||||
// // window.innerHeight + window.scrollY >= document.body.offsetHeight - 100
|
||||
// if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
|
||||
// status.value = "pending";
|
||||
// mainState.pagination.offset =
|
||||
// mainState.pagination.offset + mainState.pagination.limit;
|
||||
|
||||
if (hits.length > 0) {
|
||||
// Use spread operator to create new array reference
|
||||
loadedItems.value = [...loadedItems.value, ...hits];
|
||||
} else {
|
||||
hasMore.value = false;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
hasMore.value = false;
|
||||
|
||||
// console.error("Error loading more items:", error);
|
||||
// Consider setting hasMore.value = false if you want to stop on error
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
{ distance: 100 }
|
||||
);
|
||||
// if (total.value > mainState.pagination.offset) {
|
||||
// window.clearTimeout(isScrolling.value);
|
||||
// isScrolling.value = setTimeout(() => {
|
||||
return await getLibraryList().then((res) => {
|
||||
const hits = res ?? [];
|
||||
// Use spread operator to create new array reference
|
||||
libraryList.value = [...libraryList.value, ...hits];
|
||||
// status.value = "success";
|
||||
return res;
|
||||
});
|
||||
// }, 300);
|
||||
// } else {
|
||||
// toast.add({
|
||||
// title: "کاربر محترم",
|
||||
// description: "دیگر رکوردی جهت بارگزاری وجود ندارد.",
|
||||
// color: "success",
|
||||
// });
|
||||
// status.value = "idle";
|
||||
// }
|
||||
// } else status.value = "idle";
|
||||
};
|
||||
const { isFetching } = useInfiniteScroll(loadMore, "libraryInfiniteScroll");
|
||||
// #endregion methods
|
||||
|
||||
// components declaration
|
||||
|
@ -121,15 +137,24 @@ const CardList = defineAsyncComponent(
|
|||
</div>
|
||||
|
||||
<div
|
||||
ref="el"
|
||||
class="library-list pl-4 firefox-scrollbar grid grid-cols-2 gap-x-15 gap-y-12 md:grid-cols-3 md:gap-x-28 md:gap-y-12 lg:grid-cols-5 lg:gap-x-28 lg:gap-y-12 mx-6"
|
||||
ref="libraryInfiniteScroll"
|
||||
id="libraryInfiniteScroll"
|
||||
class="library-list pl-4 firefox-scrollbar gap-x-15 gap-y-12 md:grid-cols-3 md:gap-x-28 md:gap-y-12 lg:grid-cols-5 lg:gap-x-28 lg:gap-y-12 mx-6"
|
||||
:class="{ 'grid grid-cols-2': libraryList?.length }"
|
||||
>
|
||||
<!-- Client-side loaded content -->
|
||||
<card-list
|
||||
no-data-text="هنوز چیزی ذخیره نکردهاید!"
|
||||
no-data-icon="/img/haditha/no-data.png"
|
||||
:list="loadedItems"
|
||||
:list="libraryList"
|
||||
no-data-text="به زودی لیست کتاب ها بروزرسانی خواهد شد."
|
||||
no-data-icon=""
|
||||
></card-list>
|
||||
|
||||
<no-data
|
||||
class="h-full w-full flex flex-col justify-center items-center"
|
||||
v-if="libraryList?.length == 0"
|
||||
>
|
||||
<p class="no-data-text">به زودی لیست کتاب ها بروزرسانی خواهد شد.</p>
|
||||
</no-data>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -169,6 +194,7 @@ const CardList = defineAsyncComponent(
|
|||
/* padding: 1em 1.3em; */
|
||||
height: calc(100dvh - 13.5em);
|
||||
overflow-y: auto;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
.no-data-text {
|
||||
font-family: var(--font);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { useInfiniteScroll } from "@vueuse/core";
|
||||
// import { useInfiniteScroll } from "@vueuse/core";
|
||||
import * as z from "zod";
|
||||
|
||||
// const myCookie = useCookie("searchPhrase");
|
||||
|
@ -10,6 +10,7 @@ import headLinks from "@haditha/json/haditha/headLinks";
|
|||
import headMetas from "@haditha/json/haditha/headMetas";
|
||||
import hadithaApi from "@haditha/apis/hadithaApi";
|
||||
import type { Synonym } from "@haditha/types/hadithType";
|
||||
const toast = useToast();
|
||||
|
||||
// const searchTerm = useState("searchTerm", () => ''); // Tracks the searchTerm
|
||||
const offset = useState("offset", () => 0); // Tracks the current offset
|
||||
|
@ -34,15 +35,11 @@ useHead({
|
|||
|
||||
// #region refs
|
||||
// وقتی از صفحه حدیث با کلیک بر روی دکمه مشابه، وارد صفحه جستجو میشویم
|
||||
const showPrevSearch = ref(false);
|
||||
// لیست جستجو در حالت اسکرول
|
||||
// const loadedItems = ref([]);
|
||||
// لودینگ
|
||||
const loading = ref(false);
|
||||
// const showPrevSearch = ref(false);
|
||||
// هنگام اسکرول، چک میشود که ایا صفحه بعدی هم وجود دارد یا نه.
|
||||
const hasMore = ref(true);
|
||||
// عنصری که برای اسکرول استفاده میشه.
|
||||
const el = ref(null);
|
||||
// const el = ref(null);
|
||||
// پلاگین ارسال درخواست
|
||||
const httpService = useNuxtApp()["$http"];
|
||||
// استفاده از روت
|
||||
|
@ -142,9 +139,10 @@ const AutoComplationState = reactive({
|
|||
});
|
||||
const mainState = reactive({
|
||||
pagination: {
|
||||
limit: 10,
|
||||
limit: 15,
|
||||
page: 1,
|
||||
pages: 1,
|
||||
offset: 0,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -167,7 +165,7 @@ const backgroundImageStyle = computed(() => {
|
|||
// });
|
||||
let optimizedImageUrl = "/img/haditha/background.webp";
|
||||
|
||||
if (!showNoData.value) {
|
||||
if (loadedItems.value) {
|
||||
// optimizedImageUrl = img("/img/haditha/sub-header-bgi.webp", {
|
||||
// quality: 80,
|
||||
// });
|
||||
|
@ -205,117 +203,150 @@ const exitSimilarMode = () => {
|
|||
};
|
||||
// ارسال درخواست
|
||||
const sendQuery = async (payload = {}) => {
|
||||
let url = hadithaApi.search.list;
|
||||
url = url.replace("@index_key", "dhparag");
|
||||
url = url.replace("@search_type", search_type.value); // normal, and , phrase, vector, synonym
|
||||
url = url.replace("@type_key", type_key.value); // hadith, hadith_fa, hadith_ar, hadith_shr
|
||||
url = url.replace("@offset", offset.value);
|
||||
url = url.replace("@limit", mainState.pagination.limit);
|
||||
url = url.replace("@listkey", "normal");
|
||||
url = url.replace("@field_collapsed", "normal");
|
||||
try {
|
||||
let url = hadithaApi.search.list;
|
||||
url = url.replace("@index_key", "dhparag");
|
||||
url = url.replace("@search_type", search_type.value); // normal, and , phrase, vector, synonym
|
||||
url = url.replace("@type_key", type_key.value); // hadith, hadith_fa, hadith_ar, hadith_shr
|
||||
url = url.replace("@offset", offset.value);
|
||||
url = url.replace("@limit", mainState.pagination.limit);
|
||||
url = url.replace("@listkey", "normal");
|
||||
url = url.replace("@field_collapsed", "normal");
|
||||
|
||||
// اگر نوع انتخاب شود.
|
||||
const isTypeSelected =
|
||||
typeModelValue.value == "arabic" ||
|
||||
typeModelValue.value == "translations" ||
|
||||
typeModelValue.value == "descriptions";
|
||||
// اگر نوع انتخاب شود.
|
||||
const isTypeSelected =
|
||||
typeModelValue.value == "arabic" ||
|
||||
typeModelValue.value == "translations" ||
|
||||
typeModelValue.value == "descriptions";
|
||||
|
||||
if (searchTerm.value.length) {
|
||||
url = url.replace(
|
||||
"@q=none",
|
||||
`q=${isTypeSelected ? "#" + typeModelValueFa.value + " " : ""}${
|
||||
searchTerm.value
|
||||
}`
|
||||
);
|
||||
if (searchTerm.value.length) {
|
||||
url = url.replace(
|
||||
"@q=none",
|
||||
`q=${isTypeSelected ? "#" + typeModelValueFa.value + " " : ""}${
|
||||
searchTerm.value
|
||||
}`
|
||||
);
|
||||
|
||||
// if (route.query.f_aik?.length) url += `&f_aik=${route.query.f_aik}`;
|
||||
// if (route.query.f_aik?.length) url += `&f_aik=${route.query.f_aik}`;
|
||||
}
|
||||
|
||||
return await httpService
|
||||
.postRequest(url, payload)
|
||||
.then((res) => {
|
||||
total.value = res.hits.total.value ?? 0;
|
||||
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;
|
||||
})
|
||||
.catch((err) => {});
|
||||
} catch (err) {
|
||||
console.error("API Error:", err.message);
|
||||
throw err; // Re-throw the error to be handled by useAsyncData
|
||||
}
|
||||
|
||||
return await httpService.postRequest(url, payload).then((res) => {
|
||||
total.value = res.hits.total.value ?? 0;
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
||||
// Server-side initial load
|
||||
const { data: loadedItems } = await useAsyncData("search", () => sendQuery(), {
|
||||
transform: (data) => data.hits.hits,
|
||||
});
|
||||
showNoData.value = loadedItems.value?.length == 0;
|
||||
|
||||
const onBeforeSendQuery = (from) => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
history?.pushState(
|
||||
{},
|
||||
document?.title,
|
||||
route.path + `?q=${searchTerm.value}`
|
||||
);
|
||||
const {
|
||||
data: loadedItems,
|
||||
status,
|
||||
refresh,
|
||||
clear,
|
||||
error,
|
||||
execute,
|
||||
} = await useAsyncData(
|
||||
"search",
|
||||
async () => {
|
||||
if (searchTerm.value.length) {
|
||||
return await sendQuery();
|
||||
} else {
|
||||
return {
|
||||
hits: {
|
||||
hits: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
transform: (data) => data.hits.hits,
|
||||
}
|
||||
);
|
||||
|
||||
const onBeforeSendQuery = () => {
|
||||
if (status.value == "pending") return;
|
||||
status.value = "pending";
|
||||
offset.value = 0;
|
||||
|
||||
if (searchTerm.value?.length) {
|
||||
sendQuery().then((res) => {
|
||||
loadedItems.value = res.hits.hits;
|
||||
loadedItems.value = res?.hits?.hits ?? [];
|
||||
showNoData.value = loadedItems.value?.length == 0;
|
||||
loading.value = false;
|
||||
status.value = "success";
|
||||
|
||||
history?.pushState(
|
||||
{},
|
||||
document?.title,
|
||||
route.path + `?q=${searchTerm.value}`
|
||||
);
|
||||
route.query.q = searchTerm.value;
|
||||
});
|
||||
} else {
|
||||
searchTerm.value = "";
|
||||
loading.value = false;
|
||||
loadedItems.value = [];
|
||||
showNoData.value = false;
|
||||
loading.value = false;
|
||||
resetForm();
|
||||
|
||||
// searchTerm.value = "";
|
||||
// loading.value = false;
|
||||
// loadedItems.value = [];
|
||||
// showNoData.value = false;
|
||||
// loading.value = false;
|
||||
}
|
||||
};
|
||||
// Client-side infinite scroll
|
||||
useInfiniteScroll(
|
||||
el,
|
||||
async () => {
|
||||
if (!hasMore.value || loading.value) return;
|
||||
// useInfiniteScroll(
|
||||
// el,
|
||||
// async () => {
|
||||
// if (!hasMore.value || loading.value) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
// const nextPage = page.value + 1;
|
||||
await sendQuery().then((res) => {
|
||||
const hits = res.hits.hits;
|
||||
// loading.value = true;
|
||||
// try {
|
||||
// // const nextPage = page.value + 1;
|
||||
// await sendQuery().then((res) => {
|
||||
// const hits = res.hits.hits;
|
||||
|
||||
if (hits.length) {
|
||||
loadedItems.value.push(...hits);
|
||||
} else {
|
||||
hasMore.value = false;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
{ distance: 100 }
|
||||
);
|
||||
// if (hits.length) {
|
||||
// loadedItems.value.push(...hits);
|
||||
// } else {
|
||||
// hasMore.value = false;
|
||||
// }
|
||||
// });
|
||||
// } finally {
|
||||
// loading.value = false;
|
||||
// }
|
||||
// },
|
||||
// { distance: 100 }
|
||||
// );
|
||||
// دکمه جستجو کردن
|
||||
const onSearchButtonClick = () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
if (status.value == "pending") return;
|
||||
status.value = "pending";
|
||||
sendQuery().then((res) => {
|
||||
loadedItems.value = res.hits.hits;
|
||||
showNoData.value = loadedItems.value?.length == 0;
|
||||
loading.value = false;
|
||||
status.value = "idle";
|
||||
});
|
||||
};
|
||||
const resetForm = () => {
|
||||
clear();
|
||||
searchTerm.value = "";
|
||||
loadedItems.value = [];
|
||||
route.query.q = null;
|
||||
// loadedItems.value = [];
|
||||
status.value = "idle";
|
||||
showNoData.value = false;
|
||||
loading.value = false;
|
||||
history?.pushState({}, document?.title, route.path);
|
||||
};
|
||||
|
||||
// وقتی کاربر کلیدی فشار میدهد
|
||||
|
@ -333,10 +364,10 @@ const resetForm = () => {
|
|||
// تنظیم نوع جستجو
|
||||
const setType = (type: string) => {
|
||||
search_type.value = type;
|
||||
loadedItems.value = [];
|
||||
// loadedItems.value = [];
|
||||
offset.value = 0;
|
||||
sendQuery().then((res) => {
|
||||
loadedItems.value = res.hits.hits;
|
||||
loadedItems.value = res?.hits?.hits ?? [];
|
||||
showNoData.value = loadedItems.value?.length == 0;
|
||||
});
|
||||
};
|
||||
|
@ -455,6 +486,60 @@ const onAddNewTitle = (subTitles) => {
|
|||
showNoData.value = loadedItems.value?.length == 0;
|
||||
});
|
||||
};
|
||||
|
||||
// Using the Intersection Observer version
|
||||
|
||||
const loadMore = async () => {
|
||||
// const listElm = $event.target;
|
||||
|
||||
if (!hasMore.value) return;
|
||||
// // window.innerHeight + window.scrollY >= document.body.offsetHeight - 100
|
||||
// if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
|
||||
// status.value = "pending";
|
||||
// mainState.pagination.offset =
|
||||
// mainState.pagination.offset + mainState.pagination.limit;
|
||||
|
||||
// if (total.value > mainState.pagination.offset) {
|
||||
// window.clearTimeout(isScrolling.value);
|
||||
// isScrolling.value = setTimeout(() => {
|
||||
return await sendQuery().then((res) => {
|
||||
const hits = res?.hits?.hits ?? [];
|
||||
|
||||
if (hits.length == 0) hasMore.value = false;
|
||||
else loadedItems.value.push(...hits);
|
||||
// status.value = "success";
|
||||
return res;
|
||||
});
|
||||
// }, 300);
|
||||
// } else {
|
||||
// toast.add({
|
||||
// title: "کاربر محترم",
|
||||
// description: "دیگر رکوردی جهت بارگزاری وجود ندارد.",
|
||||
// color: "success",
|
||||
// });
|
||||
// status.value = "idle";
|
||||
// }
|
||||
// } else status.value = "idle";
|
||||
};
|
||||
const { isFetching } = useInfiniteScroll(loadMore, "searchInfiniteScroll");
|
||||
|
||||
// Add the scroll event listener when the component is mounted
|
||||
// onMounted(() => {
|
||||
// const targetElement = document.getElementById("search-list");
|
||||
|
||||
// if (targetElement) {
|
||||
// targetElement.addEventListener("scroll", loadMore);
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Remove the scroll event listener when the component is unmounted
|
||||
// onUnmounted(() => {
|
||||
// const targetElement = document.getElementById("search-list");
|
||||
// if (targetElement) {
|
||||
// targetElement.removeEventListener("scroll", loadMore);
|
||||
// }
|
||||
// });
|
||||
|
||||
// #endregion methods
|
||||
|
||||
// #region components
|
||||
|
@ -508,7 +593,7 @@ const SearchList = defineAsyncComponent(
|
|||
|
||||
<UInput
|
||||
class="w-full focus:placeholder-gray-800"
|
||||
v-model="searchTerm"
|
||||
v-model.trim="searchTerm"
|
||||
v-model:open="open"
|
||||
v-model:search-term="searchTerm"
|
||||
placeholder="هوشمند جستجو کنید..."
|
||||
|
@ -520,7 +605,7 @@ const SearchList = defineAsyncComponent(
|
|||
side: 'bottom',
|
||||
sideOffset: 4,
|
||||
}"
|
||||
:loading="loading"
|
||||
:loading="status == 'pending'"
|
||||
highlight
|
||||
highlightOnHover
|
||||
@focus="open = true"
|
||||
|
@ -554,7 +639,7 @@ const SearchList = defineAsyncComponent(
|
|||
</div>
|
||||
<div
|
||||
class="search-filter flex items-center my-3 justify-between"
|
||||
v-if="!showNoData"
|
||||
v-if="loadedItems"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<!-- #region معنایی -->
|
||||
|
@ -782,15 +867,10 @@ const SearchList = defineAsyncComponent(
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showNoData"
|
||||
v-if="!loadedItems"
|
||||
class="flex justify-center flex-col items-center mt-10"
|
||||
>
|
||||
<img
|
||||
fit="auto"
|
||||
quality="80"
|
||||
placeholder
|
||||
src="/img/haditha/logo.webp"
|
||||
/>
|
||||
<img fit="auto" quality="80" src="/img/haditha/logo.webp" />
|
||||
<div class="title">
|
||||
کاوش با
|
||||
<span class="badge-style mx-1">هوش مصنوعی</span>
|
||||
|
@ -798,33 +878,40 @@ const SearchList = defineAsyncComponent(
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- v-show="!showNoData" -->
|
||||
<div
|
||||
v-show="!showNoData"
|
||||
class="search-box-container pb-0 bg-white flex justify-center"
|
||||
:class="{ 'pt-0': loadedItems == undefined }"
|
||||
>
|
||||
<div class="search-list-contianer">
|
||||
<div class="total">
|
||||
<div v-if="loadedItems" class="total">
|
||||
<span>{{ total }}</span>
|
||||
نتیجه
|
||||
</div>
|
||||
|
||||
<!-- v-show="!loading" -->
|
||||
<div ref="el" class="search-list firefox-scrollbar">
|
||||
<!-- ref="el" -->
|
||||
<div
|
||||
ref="searchInfiniteScroll"
|
||||
id="searchInfiniteScroll"
|
||||
class="search-list firefox-scrollbar"
|
||||
:class="{ 'enable-scroll': loadedItems?.length }"
|
||||
>
|
||||
<search-list
|
||||
no-data-text="نتیجهای یافت نشد!"
|
||||
no-data-icon="/img/haditha/no-data.png"
|
||||
:total="total"
|
||||
:list="loadedItems"
|
||||
:searchTerm="searchTerm"
|
||||
:requestStatus="status"
|
||||
></search-list>
|
||||
|
||||
<!-- <no-data
|
||||
<no-data
|
||||
class="h-full w-full flex flex-col justify-center items-center"
|
||||
v-if="showNoData"
|
||||
v-if="loadedItems?.length == 0"
|
||||
>
|
||||
<img fit="auto" quality="80" src="/img/haditha/no-data.png" />
|
||||
<p class="no-data-text">"نتیجهای یافت نشد!</p>
|
||||
</no-data> -->
|
||||
</no-data>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -876,6 +963,9 @@ const SearchList = defineAsyncComponent(
|
|||
&.pb-0 {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
&.pt-0 {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.search-list-contianer {
|
||||
|
@ -898,9 +988,12 @@ const SearchList = defineAsyncComponent(
|
|||
color: #b4c2cf;
|
||||
}
|
||||
.search-list {
|
||||
padding: 1em 1.3em;
|
||||
height: calc(100dvh - 16em);
|
||||
overflow-y: auto;
|
||||
&.enable-scroll {
|
||||
padding: 1em 1.3em;
|
||||
height: calc(100dvh - 16em);
|
||||
overflow-y: auto;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
&.hadithaFavorites {
|
||||
height: calc(100dvh - 8em);
|
||||
|
|
Loading…
Reference in New Issue
Block a user