<script setup lang="ts"> // 1. Imports // 2. Metas // 3. Props // 2. Reactive State // 3. Computed Properties // 4. Functions / Methods // 5. Lifecycle Hooks // 6. Watchers // #region imports import hadithaApi from "@haditha/apis/hadithaApi"; import type { HadithResponseModel } from "@haditha/types/hadithType"; import type { HadithResponseShowModel } from "~/systems/hadith_ui/types/hadithType"; // #endregion imports // #region meta definePageMeta({ layout: false, name: "hadithaSearchShow", }); useHead({ title: `${import.meta.env.VITE_HADITH_PAGE_TITLE}`, meta: [ { name: "description", content: "کاوش با هوش مصنوعی در احادیث اسلامی" }, { name: "msapplication-TileImage", content: "/img/haditha/fav-icons/ms-icon-144x144.png", }, { name: "theme-color", content: "#ffffff" }, ], bodyAttrs: { class: import.meta.env.VITE_HADITH_SYSTEM, }, link: [ { 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 // #region props // const props = defineProps({ // selectedItem: { // type: Object, // default() { // return {}; // }, // }, // }); // #endregion props // #region refs and reactives const emit = defineEmits(["close"]); const route = useRoute(); const router = useRouter(); const loading = ref(false); const httpService = useNuxtApp()["$http"]; const state = reactive({ selectedItem: {} as HadithResponseShowModel, }); // #endregion refs and reactives // #region methods const fetchData = async () => { if (loading.value) return; loading.value = true; let url = hadithaApi.search.show; url = url.replace("@index_key", "dhparag"); url = url.replace("@id", route.params.id); // fetch search list from backend(ssr) const { data, status, error, refresh, clear } = await useHadithaSearchComposable<HadithResponseShowModel>(url, { method: "get", }); if (status.value == "success") { state.selectedItem = <HadithResponseShowModel>data.value; } loading.value = false; }; fetchData(); const goToTheSearch = (type: string) => { router.push({ name: "hadithaSearch", }); }; const goToTheChatbot = () => { router.push({ name: "hadithaChatBot", }); }; const handleFavorite = async () => { addToFavorites(state.selectedItem); // // add // if (!state.selectedItem._source.tbookmark) { // addToFavorites(state.selectedItem); // } // // delete // else { // removeFromFavorites(state.selectedItem); // } }; const addToFavorites = async (item = {}) => { let url = repoUrl() + hadithaApi.favorite.add; url = url.replace("{{data_type}}", "bookmark"); url = url.replace("{{ref_key}}", "dhparag"); const formData = { ref_id: item._id, title: item._source.content, }; httpService.postRequest(url, formData).then((res) => { // this.updateListAnswer(index, "tbookmark", 1); }); }; const removeFromFavorites = async (item = {}, index = 0) => { let url = repoUrl() + hadithaApi.favorite.deleteByRefid; url = url.replace("{{data_type}}", "bookmark"); url = url.replace("{{index_key}}", "dhparag"); url = url.replace("{{ref_id}}", item._id); const formData = { ref_id: item._id, title: item._source.title, }; httpService.postRequest(url, formData).then((res) => { // this.updateListAnswer(index, "tbookmark", 0); }); }; const handlePagination = (prevNextIndicator: string) => { if (loading.value) return; loading.value = true; let url = repoUrl() + hadithaApi.search.prevNextHadith; url = url.replace("@index_key", "dhparag"); url = url.replace("@vol_id", state.selectedItem._source.address.vol_id); url = url.replace("@parag_order", state.selectedItem._source.parag_order); url = url.replace("@step", prevNextIndicator); httpService .getRequest(url) .then((res) => { state.selectedItem = res.hits.hits?.[0]; }) .finally(() => (loading.value = false)); }; // const localCopyTextToClipboard = (text: string) => { // copyTextToClipboard(text); // }; // #endregion methods // #region hooks // onMounted(() => { // console.info("mounted"); // }); // #endregion methods </script> <template> <UContainer ui="{ base: 'sm:px-6 lg:px-4', }" class="page-inner-container sm:px-6 lg:px-4 py-8" > <div class="search-show-page"> <div class="body-header"> <span class="top-left-bgi z-0"></span> <div class="modal-title flex justify-between"> <ULink raw :to="{ name: 'haditha' }" class="flex justify-center items-center me-3" > <img fit="auto" quality="80" src="/img/haditha/haditha-title.svg" /> </ULink> <UButton icon="i-haditha-close" color="neutral" variant="ghost" class="close-btn" @click="goToTheSearch('normal')" /> </div> </div> <div class="body-content"> <div class="h-full flex flex-col justify-center z-2"> <div class="bg-container h-full"> <div class="header flex"> <UButton @click="handleFavorite" :variant=" state.selectedItem?._source?.tbookmark ? 'soft' : 'ghost' " color="primary" class="bookmark-btn" :icon=" state.selectedItem?._source?.tbookmark ? 'i-haditha-tag-active' : 'i-haditha-tag' " > </UButton> <div class="referene"> <span> نشانی: </span> {{ state.selectedItem?._source?.address?.vol_title }}، صفحه {{ state.selectedItem?._source?.address?.page_num }} </div> </div> <div class="content"> <div class="search-item"> <div class="text-arabic-section"> <div class="section-header"> <span class="section-title"> {{ state.selectedItem?._source?.meta?.hadith_masoum ?? "بدون عنوان" }} </span> <UButton @click=" copyTextToClipboard( state.selectedItem?._source?.meta?.hadith_masoum ?? '' ) " variant="ghost" class="copy-btn" label="کپی" /> </div> <div class="arabic-text"> <p>بدون متن عربی</p> </div> </div> <div class="separator"></div> <div class="text-persian-section"> <div class="section-header"> <span class="section-title"> ترجمه </span> <UButton @click=" copyTextToClipboard( state.selectedItem?._source?.content ) " variant="ghost" class="copy-btn" label="کپی" /> </div> <p class="from"> {{ state.selectedItem?._source?.meta?.hadith_masoum ?? "بدون عنوان" }}: </p> <p class="persian-text" v-html="state.selectedItem?._source?.content" ></p> </div> <div class="separator"></div> <div class="text-description-section"> <div class="section-header"> <span class="section-title"> شرح </span> <UButton @click=" copyTextToClipboard( state.selectedItem?._source?.content ) " variant="ghost" class="copy-btn" label="کپی" /> </div> <p class="description-item" v-html="state.selectedItem?._source?.content" ></p> </div> <div class="separator"></div> <div class="text-description-section"> <div class="text-sm mb-1"> <span class=""> کلیدواژگان: </span> <span class="me-1 text-gray-400 font-light" v-for="(aiClass, i) in state.selectedItem?._source ?.ai_keywords" :key="i" > {{ i > 0 ? "," : "" }} {{ aiClass }} </span> </div> <div class="text-sm"> <span class=""> دسته بندی ها: </span> <span class="me-1 text-gray-400 font-light" v-for="(aiClass, i) in state.selectedItem?._source ?.ai_classes" :key="i" > {{ i > 0 ? "," : "" }} {{ aiClass.label }} </span> </div> </div> </div> </div> </div> </div> </div> <div class="body-footer"> <div class="mt-5 z-2"> <div class="flex justify-between actions"> <UButton disabled class="similar-btn" icon="i-haditha-search-3" label="مشابه" color="neutral" variant="outline" /> <!-- @click.prevent="goToTheSearch('similar')" --> <UButton class="explore-btn" trailing-icon="i-haditha-explore" label="کاوش" variant="solid" @click.prevent="goToTheChatbot" /> </div> <div class="flex justify-between pagination"> <UButton @click="handlePagination('-1')" class="prev-haditha" label="حدیث قبل" color="" variant="soft" icon="i-haditha-chevron-right" /> <UButton @click="handlePagination('1')" class="next-haditha" label="حدیث بعد" color="" variant="soft" trailing-icon="i-haditha-chevron-left" /> </div> </div> </div> </div> </UContainer> </template> <!-- because of the buttons, using without scoped. --> <style> .search-show-page { .body-header { .modal-title { padding: 0 0.5em 1.5em; margin-bottom: 2.5em; .close-btn { color: var(--ui-color-two); /* width: 24px; */ /* height: 24px; */ padding: 0.2em; background-color: transparent; } } } .body-content { .header { .bookmark-btn { width: 49px; height: 32px; gap: 4px; border-radius: 6px; border-width: 0.5px; padding-top: 4px; padding-right: 12px; padding-bottom: 4px; padding-left: 12px; border: 0.5px solid #d9d9d9; /* background: #ffffff; */ display: flex; justify-content: center; align-items: center; /* span { */ /* width: 19; */ /* height: 21; */ /* background: #29d985; */ /* } */ } .referene { margin-right: 0.5em; width: 182; height: 32; 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: #8a92a8; display: flex; align-items: center; span { margin-left: 0.1em; font-family: IRANSansX; font-weight: 300; font-size: 12px; line-height: 18px; letter-spacing: 0%; text-align: right; color: #4d00ff; } } } .content { /* height: calc(100dvh - 29em); */ /* overflow-y: auto; */ .search-item { padding: 1em 0 1em 0.1em; .section-header { display: flex; justify-content: space-between; text-align: right; margin-bottom: 0.5em; .section-title { font-family: IRANSansX; font-weight: 400; font-size: 14px; line-height: 21px; letter-spacing: 0%; text-align: right; /* Fallback color */ color: #4be8ae; /* Gradient background */ background-image: linear-gradient( 102.02deg, #4be8ae 7.38%, #00a762 91.78% ); /* Clip the background to the text */ background-clip: text; -webkit-background-clip: text; /* For Safari */ /* Make the text transparent */ color: transparent; -webkit-text-fill-color: transparent; /* For Safari */ } .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: #8a92a8; */ } } .text-arabic-section { padding: 2em 0; .arabic-text { font-family: Takrim; font-weight: 400; font-size: 18px; line-height: 32px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); margin-bottom: 0.5em; } } .text-persian-section { padding: 2em 0; .section-header { } .from, .persian-text { font-family: Takrim; font-weight: 400; font-size: 18px; line-height: 30px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); } /* .persian-text { font-family: Takrim; font-weight: 400; font-size: 16px; line-height: 22px; letter-spacing: 0%; text-align: right; color: #626b84; margin-bottom: 0.5em; } */ } .text-description-section { padding: 2em 0; .description-item { font-family: Takrim; font-weight: 400; font-size: 18px; line-height: 30px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); /* height: 24px; gap: 4px; padding-top: 4px; padding-right: 8px; padding-bottom: 4px; padding-left: 8px; border-radius: 6px; border-width: 0.5px; border: 0.5px solid #d9d9d9; font-family: IRANSansX; font-weight: 300; font-size: 10px; line-height: 15px; letter-spacing: 0%; text-align: right; color: #8a92a8; */ } } .separator { /* border: 0.5px solid #eee; */ height: 1px; background-position: center center; background-size: contain; background-image: linear-gradient( 90deg, #ffffff 0%, #a0f5ff 30.4%, #3fc9fa 71.47%, #a7ffe7 100% ); } } } } .body-footer { .actions { margin-bottom: 1em; .similar-btn { width: 114; height: 56; gap: 8px; border-radius: 12px; border-width: 0.5px; padding-top: 8px; padding-right: 20px; padding-bottom: 8px; padding-left: 24px; background: #ffffff; border: 0.5px solid; border-image-source: linear-gradient( 102.02deg, #4be8ae 7.38%, #00a762 91.78% ); box-shadow: 0px 8px 20px 0px #0000001a; font-family: IRANSansX; font-weight: 400; font-size: 15px; line-height: 22.5px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); } .explore-btn { width: 118; height: 56; gap: 4px; border-radius: 12px; padding-top: 8px; padding-right: 24px; padding-bottom: 8px; padding-left: 20px; background: linear-gradient(268.94deg, #d284ff -0.65%, #4d00ff 104.59%); box-shadow: 0px 8px 20px 0px #0000001a; font-family: IRANSansX; font-weight: 400; font-size: 16px; line-height: 24px; letter-spacing: 0%; text-align: right; color: #fff; } } .pagination { padding: 0.7em 0px; /* width: 672; */ /* height: 56; */ justify-content: space-between; border-radius: 16px; border-width: 0.3px; padding-right: 32px; padding-left: 32px; background: #ffffff; border: 0.3px solid #e0e0e0; box-shadow: 0px 8px 20px 0px #0000001a; .prev-haditha { font-family: IRANSansX; font-weight: 300; font-size: 12px; line-height: 20px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); } .next-haditha { font-family: IRANSansX; font-weight: 300; font-size: 12px; line-height: 20px; letter-spacing: 0%; text-align: right; color: var(--ui-color-two); } } } } </style>