This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-25 16:13:02 +03:00
parent 9614e622ec
commit 5afa956360
8 changed files with 1069 additions and 43 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,109 @@
<div class="relative overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-900 uppercase dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3">Interpretations</th>
</tr>
</thead>
<tbody>
<tr class="bg-white dark:bg-gray-800">
<th
scope="row"
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
Apple MacBook Pro 17"
</th>
</tr>
</tbody>
</table>
<!-- prettier-ignore -->
<div id="quickSearchModal" tabindex="-1" aria-hidden="true" class="absolute w-96 top-14 left-[250px] z-50 hidden h-[calc(100%-1rem)] max-h-full">
<div class="relative w-full max-w-2xl max-h-full">
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header -->
<button type="button" class="hidden text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide="quickSearchModal"> <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path> </svg>
<span class="sr-only">Close modal</span>
</button>
<!-- Modal body -->
<div class="p-1 space-y-1">
<div id="quickSearchBlock-interpretations">
<table>
<thead class="text-xs text-gray-900 uppercase dark:text-gray-400">
<tr><th scope="col" class="flex items-center justify-start px-1 py-1">
<!-- prettier-ignore -->
Interpretations
</th>
</tr>
</thead>
<tbody>
<tr class="interpretationsText-0">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-2"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>
<a href="" id="interpretationsText-0"></a></th>
</tr>
<tr class="interpretationsText-1">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-2"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" /> </svg>
<a href="" id="interpretationsText-1"></a></th>
</tr>
</tbody>
</table>
</div>
<div id="quickSearchBlock-books">
<table>
<thead class="text-xs text-gray-900 uppercase dark:text-gray-400">
<tr><th scope="col" class="flex items-center justify-start px-1 py-1">
<!-- prettier-ignore -->
Books
</th>
</tr>
</thead>
<tbody>
<tr class="booksText-0">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>
<a href="" id="booksText-0"></a></th>
</tr>
<tr class="booksText-1">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>
<a href="" id="booksText-1"></a></th>
</tr>
</tbody>
</table>
</div>
<div id="quickSearchBlock-users">
<table>
<thead class="text-xs text-gray-900 uppercase dark:text-gray-400">
<tr><th scope="col" class="flex items-center justify-start px-1 py-1">
<!-- prettier-ignore -->
Users
</th>
</tr>
</thead>
<tbody>
<tr class="usersText-0">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" /> </svg>
<a href="" id="usersText-0"></a></th>
</tr>
<tr class="usersText-1">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" /> </svg>
<a href="" id="usersText-1"></a></th>
</tr>
</tbody>
</table>
</div>
<div id="quickSearchBlock-tags" class="hidden">
<table>
<thead class="text-xs text-gray-900 uppercase dark:text-gray-400">
<tr><th scope="col" class="flex items-center justify-start px-1 py-1">
<!-- prettier-ignore -->
<svg aria-hidden="true" class="w-5 h-5 mr-2 text-gray-400 group-hover:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-300" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" /> </svg>
Tags
</th>
</tr>
</thead>
<tbody>
<tr class="tagsText-0">
<th scope="row" class="px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z" /> </svg>
<a href="" id="tagsText-0"></a></th>
</tr>
<tr class="tagsText-1">
<th scope="row" class="flex items-center px-2 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<svg aria-hidden="true" class="w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z" /> </svg>
<a href="" id="tagsText-1"></a></th>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Modal footer -->
</div>
</div>
</div>

View File

@ -7,8 +7,9 @@
<svg class="w-5 h-5 text-gray-500 dark:text-gray-400" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"></path></svg>
</div>
<!-- prettier-ignore -->
<input required minlength="1" name="search_query" {% if search_query %}value={{ search_query }}{% endif %} type="text" id="mainSearchInput" class="block p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg w-80 bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" />
<input required minlength="1" autocomplete="off" name="search_query" {% if search_query %}value={{ search_query }}{% endif %} type="text" id="mainSearchInput" class="block p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg w-80 bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" />
</div>
<!-- prettier-ignore -->
<button type="button" id="global-search-button" class="md:flex px-3 py-2 text-xs text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 ml-2 font-medium rounded-lg text-center inline-flex items-center mr-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"><svg class="w-5 h-5 text-white-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 ml-0 mr-1"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 15.75l-2.489-2.489m0 0a3.375 3.375 0 10-4.773-4.773 3.375 3.375 0 004.774 4.774zM21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>Search</button>
<button type="submit" id="global-search-button" class="md:flex px-3 py-2 text-xs text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 ml-2 font-medium rounded-lg text-center inline-flex items-center mr-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"><svg class="w-5 h-5 text-white-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 ml-0 mr-1"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 15.75l-2.489-2.489m0 0a3.375 3.375 0 10-4.773-4.773 3.375 3.375 0 004.774 4.774zM21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>Search</button>
</div>
{% include 'quickSearchWindow.html' %}

View File

@ -1,8 +1,11 @@
from flask import Blueprint, render_template, request
from flask import Blueprint, render_template, request, jsonify, url_for
from sqlalchemy import func, and_, or_
from app import models as m, db
from app.controllers import create_pagination
from app.controllers.build_qa_url_using_interpretation import (
build_qa_url_using_interpretation,
)
bp = Blueprint("search", __name__)
@ -179,3 +182,64 @@ def tag_search_books():
page=pagination,
count=books.count(),
)
@bp.route("/quick_search", methods=["GET"])
def quick_search():
search_query = request.args.get("search_query", type=str, default="")
interpretations = (
m.Interpretation.query.order_by(m.Interpretation.id)
.filter((func.lower(m.Interpretation.plain_text).like(f"%{search_query}%")))
.limit(2)
)
interpretations_res = []
for interpretation in interpretations:
url_for_interpretation = build_qa_url_using_interpretation(interpretation)
interpretations_res.append(
{"label": interpretation.section.label, "url": url_for_interpretation}
)
books = (
m.Book.query.order_by(m.Book.id)
.filter((func.lower(m.Book.label).like(f"%{search_query}%")))
.limit(2)
)
books_res = []
for book in books:
url_for_book = url_for("book.collection_view", book_id=book.id)
books_res.append({"label": book.label, "url": url_for_book})
users = (
m.User.query.order_by(m.User.id)
.filter(
or_(
func.lower(m.User.username).like(f"%{search_query}%"),
func.lower(m.User.wallet_id).like(f"%{search_query}%"),
)
)
.order_by(m.User.id.asc())
.group_by(m.User.id)
.limit(2)
)
users_res = []
for user in users:
url_for_user = url_for("user.profile", user_id=user.id)
users_res.append({"label": user.username, "url": url_for_user})
tags = (
m.Tag.query.order_by(m.Tag.id)
.filter(func.lower(m.Tag.name).like(f"%{search_query}%"))
.limit(2)
)
tags_res = []
for tag in tags:
url_for_tag = url_for("search.tag_search_interpretations", tag_name=tag.name)
tags_res.append({"label": tag.name, "url": url_for_tag})
return jsonify(
{
"interpretations": interpretations_res,
"books": books_res,
"users": users_res,
"tags": tags_res,
}
)

View File

@ -13,8 +13,10 @@
"author": "",
"license": "ISC",
"dependencies": {
"@types/lodash.debounce": "^4.0.7",
"ethers": "5.5.3",
"flowbite": "^1.6.4",
"lodash.debounce": "^4.0.8",
"siwe": "1.0.0",
"tailwindcss": "^3.2.7"
},

View File

@ -1,9 +1,86 @@
import {Modal} from 'flowbite';
import type {ModalOptions, ModalInterface} from 'flowbite';
import debounce = require('lodash.debounce');
const currentSearchInput: HTMLInputElement =
document.querySelector('#mainSearchInput');
const searchDiv: HTMLElement = document.querySelector('#quickSearchModal');
const modalOptions: ModalOptions = {
closable: true,
onHide: () => {},
onShow: () => {},
onToggle: () => {},
};
const quickSearchModal: ModalInterface = new Modal(searchDiv, modalOptions);
export function quickSearch() {
const currentSearchInput = document.querySelector('#mainSearchInput');
if (currentSearchInput) {
currentSearchInput.addEventListener('input', e => {
e.preventDefault();
console.log(e);
if (currentSearchInput && searchDiv) {
currentSearchInput.addEventListener('input', debounce(onInputChange, 500));
currentSearchInput.addEventListener('blur', () => {
quickSearchModal.hide();
});
currentSearchInput.addEventListener('keypress', async e => {
if (e.key === 'Enter') {
const urlParams = new URLSearchParams({
q: currentSearchInput.value,
});
const res = await fetch('/search_interpretations?' + urlParams);
if (res.status === 200) {
window.location.replace(res.url);
} else {
return;
}
}
});
}
}
const onInputChange = async (e: any) => {
e.preventDefault();
if (currentSearchInput.value.length > 0) {
const urlParams = new URLSearchParams({
search_query: currentSearchInput.value,
});
const res = await fetch('/quick_search?' + urlParams);
const json = await res.json();
if (res.status === 200) {
for (const entity in json) {
// iterate over json from back end
const el: HTMLDivElement = document.querySelector(
`#quickSearchBlock-${entity}`,
);
const secondUnusedLink = document.querySelector(`.${entity}Text-1`);
if (secondUnusedLink) {
secondUnusedLink.classList.remove('hidden');
}
if (json[entity].length < 1) {
if (el) {
el.classList.add('hidden');
}
}
if (json[entity].length == 1) {
if (secondUnusedLink) {
secondUnusedLink.classList.add('hidden');
}
}
for (const obj in json[entity]) {
// iterate over every entity in json
el.classList.remove('hidden');
const link = document.querySelector(`#${entity}Text-${obj}`);
// taking needed html element for markup
if (link) {
// setting needed values to element
link.textContent = json[entity][obj].label;
link.setAttribute('href', json[entity][obj].url);
}
}
}
quickSearchModal.show();
} else {
return;
}
}
};

View File

@ -1113,6 +1113,18 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/lodash.debounce@^4.0.7":
version "4.0.7"
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz#0285879defb7cdb156ae633cecd62d5680eded9f"
integrity sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==
dependencies:
"@types/lodash" "*"
"@types/lodash@*":
version "4.14.194"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76"
integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
"@types/mime@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
@ -2606,6 +2618,11 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"