Work on search page
This commit is contained in:
parent
49b47bb97f
commit
1f9ed61d5b
|
@ -1,410 +1,122 @@
|
||||||
<template>
|
<script setup lang="ts">
|
||||||
<UInput
|
const props = defineProps({
|
||||||
v-model="value"
|
message: {
|
||||||
placeholder="هوشمند جستجو کنید..."
|
type: String,
|
||||||
:ui="{
|
|
||||||
trailing: '',
|
|
||||||
|
|
||||||
root: ['hadith-search-root'],
|
|
||||||
base: ['hadith-search-input'],
|
|
||||||
}"
|
|
||||||
:loading="loading"
|
|
||||||
trailing-icon="i-lucide-search"
|
|
||||||
autocomplete="on"
|
|
||||||
autofocus
|
|
||||||
highlight
|
|
||||||
@blur="onBlur"
|
|
||||||
@change="onChange"
|
|
||||||
@update:modelValue="onUpdateModel"
|
|
||||||
>
|
|
||||||
</UInput>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState } from "pinia";
|
|
||||||
import searchApi from "../../apis/searchApi.js";
|
|
||||||
import { useCommonStore } from "@stores/commonStore";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
placeholder: {
|
|
||||||
default: "جستجو در هزاران محتوای قوانین و مقرارت",
|
|
||||||
},
|
},
|
||||||
contentKey: {
|
|
||||||
default: "qasection",
|
|
||||||
},
|
|
||||||
entityTheme: {
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showAppendSearchButton: {
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
showPrepend: {
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showAppend: {
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
textSearch: {
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
modeInit: {
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
searchDomain: {
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
listAutocomplate: {
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ["getAutoComplateList"],
|
|
||||||
watch: {
|
|
||||||
modeInit(newVal = 1) {
|
|
||||||
this.mode = newVal;
|
|
||||||
},
|
|
||||||
textSearch(newVal) {
|
|
||||||
this.localTextSearch = newVal;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
// this.inputPopupState = this.inputPopupState;
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.localTextSearch = this.textSearch;
|
|
||||||
|
|
||||||
if (window.localStorage.getItem([this.historySearchRecent])) {
|
|
||||||
try {
|
|
||||||
this.historySearch = JSON.parse(
|
|
||||||
window.localStorage.getItem([this.historySearchRecent])
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
window.localStorage.removeItem([this.historySearchRecent]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
window.removeEventListener("resize", this.handleResize);
|
|
||||||
window.removeEventListener("load", this.handleResize);
|
|
||||||
document.removeEventListener("click", this.handleClickOutside);
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
value: "",
|
|
||||||
localListAutocomplate: [],
|
|
||||||
typingTimer: undefined,
|
|
||||||
doneTypingInterval: 800,
|
|
||||||
localTextSearch: "",
|
|
||||||
historySearch: [],
|
|
||||||
|
|
||||||
inputPopupState: 0,
|
|
||||||
mode: 1,
|
|
||||||
tagLiSelected: null,
|
|
||||||
inputfocused: false,
|
|
||||||
isLastKeyCodeArrow: false,
|
|
||||||
historySearchRecent: "historysearchrecent",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(useCommonStore, ["domainActiveGetter"]),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// on input changed
|
|
||||||
onUpdateModel() {
|
|
||||||
console.info("onUpdateModel");
|
|
||||||
},
|
|
||||||
// on input blur
|
|
||||||
onBlur() {
|
|
||||||
// console.info("onblue");
|
|
||||||
},
|
|
||||||
// on button click
|
|
||||||
onChange() {
|
|
||||||
console.info("onChange");
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* تنظیم آیتم انتخاب شده و شروع جستجو.
|
|
||||||
* @param {Object} navItem - آیتم انتخابشده.
|
|
||||||
*/
|
|
||||||
setDomainField(navItem) {
|
|
||||||
this.$emit("onSetDomainField", navItem);
|
|
||||||
// this.prevSearchStart();
|
|
||||||
},
|
|
||||||
async getAutoComplateList() {
|
|
||||||
this.localListAutocomplate = [];
|
|
||||||
if (this.localTextSearch == "") return;
|
|
||||||
|
|
||||||
let index_key = this.contentKey;
|
|
||||||
if (!index_key) return;
|
|
||||||
|
|
||||||
let url = searchApi.search.autoComplate;
|
|
||||||
|
|
||||||
url = url.replace("{{appname}}", buildName());
|
|
||||||
url = url.replace("{{index_key}}", index_key);
|
|
||||||
url = url.replace("{{filter}}", "q=" + this.localTextSearch);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { $api } = useNuxtApp();
|
|
||||||
const response = await $api(url, {
|
|
||||||
baseURL: repoUrl(),
|
|
||||||
});
|
});
|
||||||
|
const emit = defineEmits(["response-ready"]);
|
||||||
|
|
||||||
this.localListAutocomplate = response.hits?.hits;
|
const users = ref<Sample[]>([
|
||||||
this.inputPopupState = 3;
|
{
|
||||||
} catch (err) {}
|
label: "Leanne Graham",
|
||||||
|
value: "1",
|
||||||
|
icon: "i-lucide-clock",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
onKeyDown() {
|
label: "Ervin Howell",
|
||||||
clearTimeout(this.typingTimer);
|
value: "2",
|
||||||
this.typingTimer = undefined;
|
icon: "i-lucide-clock",
|
||||||
},
|
},
|
||||||
/**
|
{
|
||||||
* کنترل تایمر تکمیل خودکار و ارسال کوئری.
|
label: "Clementine Bauch",
|
||||||
* تایمر فعلی را پاک میکند و یک تایمر جدید با یک تاخیر مشخص تنظیم میکند تا کوئری را ارسال کند.
|
value: "3",
|
||||||
*/
|
icon: "i-lucide-clock",
|
||||||
toggleAutocomplete(event) {
|
|
||||||
// برای کلید حرکت پایین درخواست اضافی نرود
|
|
||||||
if (
|
|
||||||
event.keyCode === 40 ||
|
|
||||||
event.keyCode === 38 ||
|
|
||||||
event.keyCode === 13
|
|
||||||
) {
|
|
||||||
this.isLastKeyCodeArrow = event.keyCode === 40 || event.keyCode === 38;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLastKeyCodeArrow = false;
|
|
||||||
|
|
||||||
if (!this.inputfocused && this.inputPopupState === 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.typingTimer) {
|
|
||||||
clearTimeout(this.typingTimer);
|
|
||||||
this.typingTimer = undefined;
|
|
||||||
} else {
|
|
||||||
this.typingTimer = setTimeout(() => {
|
|
||||||
this.getAutoComplateList();
|
|
||||||
this.typingTimer = undefined;
|
|
||||||
}, this.doneTypingInterval);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
setInputFocus() {
|
export type Sample = { label: string; value: string; icon: string };
|
||||||
this.inputfocused = true;
|
|
||||||
// this.inputPopupfocused=false
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* شروع جستجو را کنترل میکند.
|
|
||||||
* @event prevSearchStart
|
|
||||||
*/
|
|
||||||
prevSearchStart(event) {
|
|
||||||
if (
|
|
||||||
this.isLastKeyCodeArrow &&
|
|
||||||
event.keyCode === 13 &&
|
|
||||||
this.inputPopupState != 0
|
|
||||||
) {
|
|
||||||
this.selectAutocomplate2();
|
|
||||||
this.isLastKeyCodeArrow = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tagLiSelected = null;
|
const searchTerm = ref("");
|
||||||
this.inputPopupState = 0;
|
const open = ref(false);
|
||||||
this.addHistorySearch(this.localTextSearch);
|
const value = ref<Sample>();
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
let tt = myEncodeQuery(this.localTextSearch);
|
// fetch history list from backend(ssr)
|
||||||
this.$emit("onSearchStart", tt);
|
// const { data: users, status } = await useFetch(
|
||||||
// this.searchStart(tt);
|
// "https://jsonplaceholder.typicode.com/users",
|
||||||
},
|
// {
|
||||||
/**
|
// transform: (data: { id: number; name: string }[]) => {
|
||||||
*نمایش سابقه جستجو.
|
// return (
|
||||||
*/
|
// data?.map((user) => ({
|
||||||
showHisory() {
|
// label: user.name,
|
||||||
setTimeout(() => {
|
// value: String(user.id),
|
||||||
if (this.localTextSearch == "") this.inputPopupState = 1;
|
// avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` },
|
||||||
else {
|
// })) || []
|
||||||
this.inputPopupState = 0;
|
// );
|
||||||
this.tagLiSelected = null;
|
// },
|
||||||
}
|
// lazy: true,
|
||||||
}, 100);
|
// }
|
||||||
},
|
// );
|
||||||
/**
|
|
||||||
* کنترل کلیکهای خارج از المان.
|
|
||||||
*/
|
|
||||||
keyupdiv(event) {
|
|
||||||
// 13:enter
|
|
||||||
// 8:backspace
|
|
||||||
if (this.inputfocused == false) return;
|
|
||||||
if (this.inputPopupState == 0 || this.inputPopupState == 2) return;
|
|
||||||
var el = "";
|
|
||||||
el =
|
|
||||||
this.inputPopupState == 1
|
|
||||||
? this.$refs["his_ul"]
|
|
||||||
: this.$refs["auto_complate_ul"];
|
|
||||||
|
|
||||||
if (!el || !el.firstChild) return;
|
const onBlur = () => {
|
||||||
|
// console.info("onBlue");
|
||||||
const selectItem = (item) => {
|
|
||||||
this.tagLiSelected = item;
|
|
||||||
this.tagLiSelected?.classList.add("selected");
|
|
||||||
this.tagLiSelected?.focus();
|
|
||||||
};
|
};
|
||||||
|
const onChange = () => {
|
||||||
|
// console.info("onChange");
|
||||||
|
};
|
||||||
|
const onUpdateModel = (newVal) => {
|
||||||
|
// console.info("onUpdateModel", newVal);
|
||||||
|
};
|
||||||
|
const onSearch = () => {
|
||||||
|
console.info("onSearch");
|
||||||
|
};
|
||||||
|
const onKeyDown = () => {
|
||||||
|
// console.info("onKeyDown");
|
||||||
|
};
|
||||||
|
const onKeyUp = () => {
|
||||||
|
// console.info("onKeyUp");
|
||||||
|
};
|
||||||
|
const onSend = () => {
|
||||||
|
console.info("onSend");
|
||||||
|
|
||||||
// 40: arrow down
|
emit("response-ready", "Hello from Child!");
|
||||||
// 38: arrow up
|
|
||||||
if (this.inputfocused == true && event.keyCode === 40) {
|
|
||||||
if (this.tagLiSelected) {
|
|
||||||
this.tagLiSelected?.classList.remove("selected");
|
|
||||||
const next = this.tagLiSelected?.nextSibling || el.firstChild;
|
|
||||||
selectItem(next);
|
|
||||||
} else {
|
|
||||||
selectItem(el?.firstChild);
|
|
||||||
}
|
|
||||||
} else if (this.inputfocused == true && event.keyCode === 38) {
|
|
||||||
if (this.tagLiSelected) {
|
|
||||||
this.tagLiSelected?.classList.remove("selected");
|
|
||||||
const prev = this.tagLiSelected?.previousSibling || el.lastChild;
|
|
||||||
selectItem(prev);
|
|
||||||
} else {
|
|
||||||
selectItem(el?.lastChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 46: delete
|
|
||||||
else if (this.inputfocused == true && event.keyCode === 46) {
|
|
||||||
let index = this.tagLiSelected?.getAttribute("data-key");
|
|
||||||
|
|
||||||
this.removeHistorySearch(index);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClickOutside() {
|
|
||||||
if (this.inputPopupState == 1 || this.inputPopupState == 3) {
|
|
||||||
this.inputPopupState = 0;
|
|
||||||
this.tagLiSelected = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectAutocomplate(item) {
|
|
||||||
this.tagLiSelected = null;
|
|
||||||
this.inputPopupState = 0;
|
|
||||||
this.localTextSearch = item;
|
|
||||||
|
|
||||||
this.$emit("onSearchStart", this.localTextSearch);
|
|
||||||
// this.$emit("onSearchStart", {
|
|
||||||
// textSearch: this.localTextSearch,
|
|
||||||
// searchItem: item,
|
|
||||||
// });
|
|
||||||
},
|
|
||||||
|
|
||||||
selectHistorySearch(item) {
|
|
||||||
this.localTextSearch = item;
|
|
||||||
this.$emit("onSearchStart", this.localTextSearch);
|
|
||||||
},
|
|
||||||
|
|
||||||
removeHistorySearch(x) {
|
|
||||||
this.tagLiSelected = null;
|
|
||||||
this.historySearch.splice(x, 1);
|
|
||||||
this.saveHistorySearch();
|
|
||||||
},
|
|
||||||
saveHistorySearch() {
|
|
||||||
const parsed = JSON.stringify(this.historySearch);
|
|
||||||
window.localStorage.setItem([this.historySearchRecent], parsed);
|
|
||||||
},
|
|
||||||
getHighlightAutocomplate(item) {
|
|
||||||
if (!item) return "";
|
|
||||||
|
|
||||||
let html = "";
|
|
||||||
|
|
||||||
let key = "title";
|
|
||||||
if (this.contentKey == "qasection" || this.contentKey == "rgsection") {
|
|
||||||
key = "qanon_title";
|
|
||||||
if (item?.highlight[key]) html = item.highlight[key][0];
|
|
||||||
if (!html) {
|
|
||||||
let key1 = key + ".ph";
|
|
||||||
if (item?.highlight[key1]) html = item.highlight[key1][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!html) {
|
|
||||||
let key1 = key + ".fa";
|
|
||||||
if (item?.highlight[key1]) html = item.highlight[key1][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let key2 = "ts_date";
|
|
||||||
if (item?._source[key2]) {
|
|
||||||
html += `<span style="color: #a7a098;"> - تاریخ: ${item._source[key2]}</span>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.contentKey == "sanad") {
|
|
||||||
Object.values(item?.highlight).forEach((element, index) => {
|
|
||||||
html += element[0];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
addHistorySearch(newSearch = "") {
|
|
||||||
if (newSearch == "") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var index = this.historySearch.indexOf(newSearch);
|
|
||||||
if (index != -1) {
|
|
||||||
this.historySearch.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.historySearch.unshift(newSearch);
|
|
||||||
this.saveHistorySearch();
|
|
||||||
},
|
|
||||||
saveHistorySearch() {
|
|
||||||
const parsed = JSON.stringify(this.historySearch);
|
|
||||||
window.localStorage.setItem([this.historySearchRecent], parsed);
|
|
||||||
},
|
|
||||||
|
|
||||||
selectAutocomplate2(item) {
|
|
||||||
if (!item) {
|
|
||||||
if (this.localListAutocomplate.length) {
|
|
||||||
item = this.localListAutocomplate[this.tagLiSelected?.value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = "title";
|
|
||||||
if (this.contentKey == "qasection" || this.contentKey == "rgsection")
|
|
||||||
key = "qanon_title";
|
|
||||||
|
|
||||||
this.inputfocused = false;
|
|
||||||
this.searchinput?.blur();
|
|
||||||
this.localTextSearch = item?._source[key];
|
|
||||||
|
|
||||||
this.$emit("onSearchStart", this.localTextSearch);
|
|
||||||
// this.$emit("onSearchStart", {
|
|
||||||
// textSearch: this.localTextSearch,
|
|
||||||
// searchItem: item,
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (!item) {
|
|
||||||
this.localTextSearch = this.tagLiSelected?.innerText;
|
|
||||||
this.addHistorySearch(this.localTextSearch);
|
|
||||||
|
|
||||||
let tt = myEncodeQuery(this.localTextSearch);
|
|
||||||
|
|
||||||
this.$emit("onSearchStart", tt);
|
|
||||||
// this.$emit("onSearchStart", { textSearch: tt, searchItem: item });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inputPopupState = 0;
|
|
||||||
this.tagLiSelected = null;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="hadith-search-root">
|
||||||
|
<UInputMenu
|
||||||
|
class="w-full"
|
||||||
|
:items="users || []"
|
||||||
|
v-model="value"
|
||||||
|
v-model:open="open"
|
||||||
|
v-model:search-term="searchTerm"
|
||||||
|
placeholder="هوشمند جستجو کنید..."
|
||||||
|
:ui="{
|
||||||
|
base: ['hadith-search-input'],
|
||||||
|
}"
|
||||||
|
:content="{
|
||||||
|
align: 'start',
|
||||||
|
side: 'bottom',
|
||||||
|
sideOffset: 4,
|
||||||
|
}"
|
||||||
|
:loading="loading"
|
||||||
|
highlight
|
||||||
|
highlightOnHover
|
||||||
|
@focus="open = true"
|
||||||
|
@blur="onBlur"
|
||||||
|
@change="onChange"
|
||||||
|
@update:modelValue="onUpdateModel"
|
||||||
|
@update:searchTerm="onUpdateModel"
|
||||||
|
@keydown="onKeyDown"
|
||||||
|
@keyup="onKeyUp"
|
||||||
|
@keydown.enter="onSend"
|
||||||
|
>
|
||||||
|
</UInputMenu>
|
||||||
|
|
||||||
|
<UButton class="my-trailing-button">
|
||||||
|
<UIcon @click.prevent="onSearch" name="i-lucide-search" />
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.hadith-search-root {
|
.hadith-search-root {
|
||||||
width: 656px;
|
position: relative;
|
||||||
|
max-width: 656px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 1em;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: "";
|
||||||
|
|
||||||
|
@ -416,24 +128,22 @@ export default {
|
||||||
backdrop-filter: blur(60px);
|
backdrop-filter: blur(60px);
|
||||||
background: linear-gradient(137.41deg, #ffffff -42.82%, #e5e0ff 87.9%);
|
background: linear-gradient(137.41deg, #ffffff -42.82%, #e5e0ff 87.9%);
|
||||||
filter: blur(60px);
|
filter: blur(60px);
|
||||||
/* transform: rotate(180deg); */
|
|
||||||
|
|
||||||
width: 626px;
|
width: 626px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
z-index: 1;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.my-trailing-button {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
& > span {
|
z-index: 1;
|
||||||
z-index:3;
|
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
/* padding-bottom: 6px; */
|
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
/* border-bottom-width: 1px; */
|
|
||||||
background: linear-gradient(320.71deg, #b9fde0 6.56%, #e4f9f0 69.69%);
|
background: linear-gradient(320.71deg, #b9fde0 6.56%, #e4f9f0 69.69%);
|
||||||
left: 12px;
|
left: 12px;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -443,31 +153,23 @@ export default {
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
background: linear-gradient(320.71deg, #90ceb3 6.56%, #daf1e8 69.69%);
|
background: linear-gradient(320.71deg, #54ecaa 6.56%, #b6f0d9 69.69%);
|
||||||
}
|
}
|
||||||
|
|
||||||
& > span {
|
& > span {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
/* border-width: 1.5px; */
|
|
||||||
/* border: 1.5px solid; */
|
|
||||||
|
|
||||||
/* border-image-source: linear-gradient(
|
background-image: linear-gradient(102.02deg, #4be8ae 7.38%, #00a762 91.78%);
|
||||||
102.02deg,
|
|
||||||
#4be8ae 7.38%,
|
|
||||||
#00a762 91.78%
|
|
||||||
); */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.hadith-search-input {
|
.hadith-search-input {
|
||||||
z-index: 2;
|
z-index: 0;
|
||||||
|
|
||||||
height: 72px;
|
height: 72px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
padding-right: 24px;
|
padding-right: 12px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
|
@ -100,20 +100,28 @@ const leftItem = ref([
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const isMobile = ref(false);
|
||||||
|
const rerenderNavigation = ref(1);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (window?.outerWidth < 576)
|
if (window?.outerWidth < 576) {
|
||||||
|
isMobile.value = true;
|
||||||
|
console.info("is less than 576");
|
||||||
|
|
||||||
items.value = items.value.filter((item) => item.to != "/hadith/favorites");
|
items.value = items.value.filter((item) => item.to != "/hadith/favorites");
|
||||||
|
rerenderNavigation.value++;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed bottom-2 lg:top-2 right-0 left-0">
|
<div class="fixed bottom-2 lg:bottom-auto lg:top-2 right-0 left-0">
|
||||||
<client-only>
|
|
||||||
<UContainer class="flex justify-center my-navbar mx-3 lg:mx-auto">
|
<UContainer class="flex justify-center my-navbar mx-3 lg:mx-auto">
|
||||||
<UNavigationMenu
|
<UNavigationMenu
|
||||||
highlight
|
:key="rerenderNavigation"
|
||||||
|
:disableHoverTrigge="isMobile"
|
||||||
:items="items"
|
:items="items"
|
||||||
class="data-[orientation=horizontal]:border-0 border-(--ui-border) data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-48"
|
class="data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-48"
|
||||||
/>
|
/>
|
||||||
<div class="hidden lg:flex items-center">
|
<div class="hidden lg:flex items-center">
|
||||||
<template v-for="(item, index) in leftItem">
|
<template v-for="(item, index) in leftItem">
|
||||||
|
@ -138,7 +146,6 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
</client-only>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -167,10 +174,55 @@ onMounted(() => {
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
li {
|
li {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
@media screen and (max-width: 991.99px) {
|
@media screen and (max-width: 991.99px) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
&::before {
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&::before {
|
||||||
|
background-color: color-mix(in oklab, #00a762 50%, transparent);
|
||||||
|
box-shadow: 0px 4px 10px 0px #00745933;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max-width: 112px;
|
||||||
|
height: 48px;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
padding-left: 16px;
|
||||||
|
|
||||||
|
font-family: IRANSansX;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 21px;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&[data-active=""] {
|
||||||
|
background: linear-gradient(
|
||||||
|
102.02deg,
|
||||||
|
#4be8ae 7.38%,
|
||||||
|
#00a762 91.78%
|
||||||
|
);
|
||||||
|
box-shadow: 0px 4px 10px 0px #00745933;
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.hide-label {
|
.hide-label {
|
||||||
.truncate {
|
.truncate {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
93
components/hadith/hero-page/SectionOne.vue
Normal file
93
components/hadith/hero-page/SectionOne.vue
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<template>
|
||||||
|
<section class="section-one flex flex-col justify-center">
|
||||||
|
<div class="bg-container h-full" :style="backgroundImageStyle">
|
||||||
|
<navigation-menu></navigation-menu>
|
||||||
|
|
||||||
|
<div class="text-logo flex justify-center flex-col items-center">
|
||||||
|
<NuxtImg fit="auto" quality="80" placeholder src="/img/logo.png" />
|
||||||
|
<div class="title">
|
||||||
|
کاوش با
|
||||||
|
<span class="badge-style"> هوش مصنوعی </span>
|
||||||
|
در احادیث اسلامی
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-box-container flex justify-center">
|
||||||
|
<auto-complation></auto-complation>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
logo: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
backgroundImageStyle() {
|
||||||
|
// Use $img to generate an optimized image URL
|
||||||
|
const optimizedImageUrl = this.$img("/img/background.png", {
|
||||||
|
quality: 80,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${optimizedImageUrl}), linear-gradient(199.05deg, #ffffff 9.99%, #e4fff7 42.07%, #ffffff 97.12%)`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
NavigationMenu: defineAsyncComponent(() =>
|
||||||
|
import("@hadith/components/hadith/NavigationMenu.vue")
|
||||||
|
),
|
||||||
|
AutoComplation: defineAsyncComponent(() =>
|
||||||
|
import("@hadith/components/hadith/AutoComplation.vue")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.section-one {
|
||||||
|
.bg-container {
|
||||||
|
height: 521px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
/* background-attachment: fixed; */
|
||||||
|
/* background-image: url("/img/background.svg"),
|
||||||
|
linear-gradient(199.05deg, #ffffff 9.99%, #e4fff7 42.07%, #ffffff 97.12%); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-logo {
|
||||||
|
padding-top: 10em;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-top: 3.5em;
|
||||||
|
font-family: IRANSansX;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 21px;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
text-align: center;
|
||||||
|
color: #1b2132;
|
||||||
|
}
|
||||||
|
.badge-style {
|
||||||
|
width: 100;
|
||||||
|
height: 23;
|
||||||
|
border-radius: 40px;
|
||||||
|
padding-right: 8px;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
padding-left: 8px;
|
||||||
|
gap: 10px;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
background: linear-gradient(270.29deg, #d284ff 8.12%, #4d00ff 109.58%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box-container {
|
||||||
|
padding-top: 1em;
|
||||||
|
padding-bottom: 4em; /*64px */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
123
components/hadith/hero-page/SectionTwo.vue
Normal file
123
components/hadith/hero-page/SectionTwo.vue
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<template>
|
||||||
|
<section class="section-two">
|
||||||
|
<div class="flex flex-col items-center py-6">
|
||||||
|
<div>قابلیت ها</div>
|
||||||
|
<div>
|
||||||
|
<NuxtImg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
fit="auto"
|
||||||
|
quality="80"
|
||||||
|
placeholder
|
||||||
|
src="/img/chevron-down.svg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col lg:flex-row">
|
||||||
|
<div class="my-card card-one basis-full flex justify-center items-center">
|
||||||
|
<div class="inner-container">
|
||||||
|
<div>
|
||||||
|
<p class="title">جستجوی معنایی</p>
|
||||||
|
<p class="description">ارائه نتایج دقیق و معنادار از میان</p>
|
||||||
|
<p class="description">حجم انبوه متون حدیثی</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NuxtImg
|
||||||
|
fit="auto"
|
||||||
|
quality="80"
|
||||||
|
placeholder
|
||||||
|
src="/img/card-one.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="my-card card-two basis-full flex justify-center items-center">
|
||||||
|
<div class="inner-container">
|
||||||
|
<div class="">
|
||||||
|
<p class="title">جستجوی مترادفها</p>
|
||||||
|
<p class="description">یافتن سریع واژگان مرتبط برای</p>
|
||||||
|
<p class="description">درک بهتر مفاهیم حدیثی</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NuxtImg
|
||||||
|
fit="auto"
|
||||||
|
quality="80"
|
||||||
|
placeholder
|
||||||
|
src="/img/card-two.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="my-card card-three basis-full flex flex-col justify-center items-center"
|
||||||
|
>
|
||||||
|
<div class="inner-container">
|
||||||
|
<div>
|
||||||
|
<p class="title">مشابهتیابی حدیث</p>
|
||||||
|
<p class="description">امکان یافتن احادیث یا مفاهیمی</p>
|
||||||
|
<p class="description">با معنای مشابه یک حدیث</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NuxtImg
|
||||||
|
fit="auto"
|
||||||
|
quality="80"
|
||||||
|
placeholder
|
||||||
|
src="/img/card-three.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.section-two {
|
||||||
|
font-weight: 200;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 30px;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.my-card {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: auto;
|
||||||
|
height: 660px;
|
||||||
|
|
||||||
|
.inner-container {
|
||||||
|
max-width: 21.25em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 36px;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
color: #1b2132;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 30px;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
text-align: right;
|
||||||
|
color: #626b84;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-one {
|
||||||
|
background-image: url("/img/card-one-bgi.png"),
|
||||||
|
linear-gradient(134.17deg, #ffffff -9.81%, #e5e0ff 87.62%);
|
||||||
|
}
|
||||||
|
&.card-two {
|
||||||
|
background-image: url("/img/card-two-bgi.png"),
|
||||||
|
linear-gradient(329.16deg, #b9fde0 13.45%, #eefff8 63.57%);
|
||||||
|
}
|
||||||
|
&.card-three {
|
||||||
|
background-image: url("/img/card-three-bgi.png"),
|
||||||
|
linear-gradient(134.17deg, #ffffff -9.81%, #e5e0ff 87.62%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,101 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<HadithLayout :menu="sidbarMenu">
|
<HadithLayout>
|
||||||
<section class="section-one flex flex-col justify-center">
|
<section-one></section-one>
|
||||||
<div class="bg-container h-full" :style="backgroundImageStyle">
|
<section-two></section-two>
|
||||||
<navigation-menu></navigation-menu>
|
|
||||||
|
|
||||||
<div class="text-logo flex justify-center flex-col items-center">
|
|
||||||
<NuxtImg fit="auto" quality="80" placeholder src="/img/logo.png" />
|
|
||||||
<div class="title">
|
|
||||||
کاوش با
|
|
||||||
<span class="badge-style"> هوش مصنوعی </span>
|
|
||||||
در احادیث اسلامی
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="search-box-container flex justify-center">
|
|
||||||
<auto-complation></auto-complation>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="section-two">
|
|
||||||
<div class="flex flex-col items-center py-6">
|
|
||||||
<div>قابلیت ها</div>
|
|
||||||
<div>
|
|
||||||
<NuxtImg
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
fit="auto"
|
|
||||||
quality="80"
|
|
||||||
placeholder
|
|
||||||
src="/img/chevron-down.svg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col lg:flex-row">
|
|
||||||
<div class="my-card card-one basis-full flex justify-center items-center">
|
|
||||||
<div class="inner-container">
|
|
||||||
<div>
|
|
||||||
<p class="title">جستجوی معنایی</p>
|
|
||||||
<p class="description">ارائه نتایج دقیق و معنادار از میان</p>
|
|
||||||
<p class="description">حجم انبوه متون حدیثی</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<NuxtImg
|
|
||||||
fit="auto"
|
|
||||||
quality="80"
|
|
||||||
placeholder
|
|
||||||
src="/img/card-one.png"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="my-card card-two basis-full flex justify-center items-center">
|
|
||||||
<div class="inner-container">
|
|
||||||
<div class="">
|
|
||||||
<p class="title">جستجوی مترادفها</p>
|
|
||||||
<p class="description">یافتن سریع واژگان مرتبط برای</p>
|
|
||||||
<p class="description">درک بهتر مفاهیم حدیثی</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<NuxtImg
|
|
||||||
fit="auto"
|
|
||||||
quality="80"
|
|
||||||
placeholder
|
|
||||||
src="/img/card-two.png"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="my-card card-three basis-full flex flex-col justify-center items-center"
|
|
||||||
>
|
|
||||||
<div class="inner-container">
|
|
||||||
<div>
|
|
||||||
<p class="title">مشابهتیابی حدیث</p>
|
|
||||||
<p class="description">امکان یافتن احادیث یا مفاهیمی</p>
|
|
||||||
<p class="description">با معنای مشابه یک حدیث</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<NuxtImg
|
|
||||||
fit="auto"
|
|
||||||
quality="80"
|
|
||||||
placeholder
|
|
||||||
src="/img/card-three.png"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</HadithLayout>
|
</HadithLayout>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { useStorage } from "@vueuse/core";
|
|
||||||
import { mapActions, mapState } from "pinia";
|
|
||||||
|
|
||||||
import { useHadithStore } from "@hadith/stores/hadithStore";
|
|
||||||
import { useCommonStore } from "~/stores/commonStore";
|
|
||||||
import hadithApi from "@hadith/apis/hadithApi.js";
|
|
||||||
import navbarMenu from "@hadith/json/hadith/menu.json";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "hadith",
|
name: "hadith",
|
||||||
|
@ -115,117 +24,12 @@ export default {
|
||||||
name: "hadith",
|
name: "hadith",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
|
||||||
this.httpService = useNuxtApp()["$http"];
|
|
||||||
},
|
|
||||||
|
|
||||||
async mounted() {
|
|
||||||
let schemaExist = this.searchActiveTabGetter && this.searchSchemaGetter;
|
|
||||||
|
|
||||||
if (!schemaExist) this.getSchemas();
|
|
||||||
else this.setSearchDomain(this.searchActiveTabGetter);
|
|
||||||
|
|
||||||
if (window.outerWidth < 992) {
|
|
||||||
this.$store.commit("TOGGLE_SIDEBAR_MENU");
|
|
||||||
this.showMobileFilterList = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
httpService: {},
|
|
||||||
logo: "",
|
|
||||||
sidbarMenuDefault: navbarMenu,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
// ...mapState(useHadithStore, [
|
|
||||||
// "domainActiveGetter",
|
|
||||||
// "searchActiveTabGetter",
|
|
||||||
// "searchSchemaGetter",
|
|
||||||
// "searchSynonymTitleGetter",
|
|
||||||
// ]),
|
|
||||||
...mapState(useCommonStore, [
|
|
||||||
"currentUser",
|
|
||||||
"organNameGetter",
|
|
||||||
"isSidebarCollapsed",
|
|
||||||
"userPermisionGetter",
|
|
||||||
]),
|
|
||||||
|
|
||||||
sidbarMenu() {
|
|
||||||
return this.sidbarMenuDefault;
|
|
||||||
},
|
|
||||||
|
|
||||||
backgroundImageStyle() {
|
|
||||||
// Use $img to generate an optimized image URL
|
|
||||||
const optimizedImageUrl = this.$img("/img/background.png", {
|
|
||||||
quality: 80,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
backgroundImage: `url(${optimizedImageUrl}), linear-gradient(199.05deg, #ffffff 9.99%, #e4fff7 42.07%, #ffffff 97.12%)`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(useCommonStore, [
|
|
||||||
"TOGGLE_SIDEBAR_MENU",
|
|
||||||
"sidebarCollapsedSetter",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// ...mapActions(useHadithStore, [
|
|
||||||
// "searchActiveTabSetter",
|
|
||||||
// "searchSchemaSetter",
|
|
||||||
// "domainActiveSetter",
|
|
||||||
// "searchSynonymTitleSetter",
|
|
||||||
// ]),
|
|
||||||
|
|
||||||
async getSchemas() {
|
|
||||||
let localStoageSearchSchema = useStorage("searchSchema", undefined).value;
|
|
||||||
|
|
||||||
if (localStoageSearchSchema) {
|
|
||||||
let searchSchema = JSON.parse(localStoageSearchSchema);
|
|
||||||
this.searchSchemaSetter(searchSchema);
|
|
||||||
this.searchActiveTabSetter(searchSchema[0]);
|
|
||||||
} else {
|
|
||||||
const payload = {
|
|
||||||
organ: this.organNameGetter,
|
|
||||||
system: "search",
|
|
||||||
build_state: buildState(),
|
|
||||||
};
|
|
||||||
const url = repoUrl() + hadithApi.schema.list;
|
|
||||||
|
|
||||||
this.httpService
|
|
||||||
.postRequest(url, payload)
|
|
||||||
.then((res) => {
|
|
||||||
this.searchSchemaSetter(res.data.search);
|
|
||||||
this.searchActiveTabSetter(res.data.search[0]);
|
|
||||||
this.fetchingData = false;
|
|
||||||
|
|
||||||
const toast = useToast();
|
|
||||||
toast.add({
|
|
||||||
title: "Success",
|
|
||||||
description: "Your action was completed successfully.",
|
|
||||||
color: "success",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
this.fetchingData = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
AutoComplation: defineAsyncComponent(() =>
|
SectionOne: defineAsyncComponent(() =>
|
||||||
import("@hadith/components/hadith/AutoComplation.vue")
|
import("@hadith/components/hadith/hero-page/SectionOne.vue")
|
||||||
),
|
),
|
||||||
NavigationMenu: defineAsyncComponent(() =>
|
SectionTwo: defineAsyncComponent(() =>
|
||||||
import("@hadith/components/hadith/NavigationMenu.vue")
|
import("@hadith/components/hadith/hero-page/SectionTwo.vue")
|
||||||
),
|
|
||||||
AutoComplation: defineAsyncComponent(() =>
|
|
||||||
import("@hadith/components/hadith/AutoComplation.vue")
|
|
||||||
),
|
),
|
||||||
HadithLayout: defineAsyncComponent(() =>
|
HadithLayout: defineAsyncComponent(() =>
|
||||||
import("@hadith/layouts/HadithLayout.vue")
|
import("@hadith/layouts/HadithLayout.vue")
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user