working on

This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-23 15:52:49 +03:00
parent 75c0b6b3a8
commit d8d0db943d
21 changed files with 567 additions and 181 deletions

View File

@ -13,6 +13,7 @@
"cSpell.words": [ "cSpell.words": [
"bookname", "bookname",
"Btns", "Btns",
"CLEANR",
"flowbite", "flowbite",
"jsonify", "jsonify",
"pydantic", "pydantic",

View File

@ -26,6 +26,7 @@ def create_app(environment="development"):
vote_blueprint, vote_blueprint,
approve_blueprint, approve_blueprint,
star_blueprint, star_blueprint,
search_blueprint,
) )
from app.models import ( from app.models import (
User, User,
@ -57,6 +58,7 @@ def create_app(environment="development"):
app.register_blueprint(vote_blueprint) app.register_blueprint(vote_blueprint)
app.register_blueprint(approve_blueprint) app.register_blueprint(approve_blueprint)
app.register_blueprint(star_blueprint) app.register_blueprint(star_blueprint)
app.register_blueprint(search_blueprint)
# Set up flask login. # Set up flask login.
@login_manager.user_loader @login_manager.user_loader

View File

@ -2,3 +2,4 @@
from .pagination import create_pagination from .pagination import create_pagination
from .breadcrumbs import create_breadcrumbs from .breadcrumbs import create_breadcrumbs
from .book_verify import register_book_verify_route, book_validator from .book_verify import register_book_verify_route, book_validator
from .clean_html import clean_html

View File

@ -0,0 +1,9 @@
import re
# as per recommendation from @freylis, compile once only
CLEANR = re.compile("<.*?>")
def clean_html(raw_html):
clean_text = re.sub(CLEANR, "", raw_html)
return clean_text

View File

@ -13,4 +13,3 @@ from .interpretation import CreateInterpretationForm, EditInterpretationForm
from .comment import CreateCommentForm from .comment import CreateCommentForm
from .vote import VoteForm from .vote import VoteForm
from .comment import CreateCommentForm, DeleteCommentForm, EditCommentForm from .comment import CreateCommentForm, DeleteCommentForm, EditCommentForm
from .search import SearchForm

View File

@ -1,8 +0,0 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class SearchForm(FlaskForm):
search_query = StringField("SearchQuery", [DataRequired()])
submit = SubmitField("Submit")

View File

@ -8,6 +8,7 @@ class Interpretation(BaseModel):
__tablename__ = "interpretations" __tablename__ = "interpretations"
text = db.Column(db.Text, unique=False, nullable=False) text = db.Column(db.Text, unique=False, nullable=False)
plain_text = db.Column(db.Text, unique=False)
approved = db.Column(db.Boolean, default=False) approved = db.Column(db.Boolean, default=False)
marked = db.Column(db.Boolean, default=False) marked = db.Column(db.Boolean, default=False)

View File

@ -1483,6 +1483,14 @@ input:checked + .toggle-bg {
height: 100vh; height: 100vh;
} }
.h-2 {
height: 0.5rem;
}
.h-2\.5 {
height: 0.625rem;
}
.max-h-40 { .max-h-40 {
max-height: 10rem; max-height: 10rem;
} }
@ -1583,6 +1591,14 @@ input:checked + .toggle-bg {
width: 100vw; width: 100vw;
} }
.w-2 {
width: 0.5rem;
}
.w-2\.5 {
width: 0.625rem;
}
.max-w-2xl { .max-w-2xl {
max-width: 42rem; max-width: 42rem;
} }
@ -2133,6 +2149,11 @@ input:checked + .toggle-bg {
background-color: rgb(255 255 255 / 0.5); background-color: rgb(255 255 255 / 0.5);
} }
.bg-green-500 {
--tw-bg-opacity: 1;
background-color: rgb(14 159 110 / var(--tw-bg-opacity));
}
.bg-opacity-50 { .bg-opacity-50 {
--tw-bg-opacity: 0.5; --tw-bg-opacity: 0.5;
} }
@ -2612,6 +2633,11 @@ input:checked + .toggle-bg {
background-color: rgb(255 255 255 / var(--tw-bg-opacity)); background-color: rgb(255 255 255 / var(--tw-bg-opacity));
} }
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:bg-gradient-to-bl:hover { .hover\:bg-gradient-to-bl:hover {
background-image: linear-gradient(to bottom left, var(--tw-gradient-stops)); background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
} }
@ -2646,6 +2672,10 @@ input:checked + .toggle-bg {
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
.hover\:underline:hover {
text-decoration-line: underline;
}
.focus\:border-blue-500:focus { .focus\:border-blue-500:focus {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(63 131 248 / var(--tw-border-opacity)); border-color: rgb(63 131 248 / var(--tw-border-opacity));
@ -2734,6 +2764,11 @@ input:checked + .toggle-bg {
color: rgb(17 24 39 / var(--tw-text-opacity)); color: rgb(17 24 39 / var(--tw-text-opacity));
} }
.group:hover .group-hover\:text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:translate-y-0 { .peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:translate-y-0 {
--tw-translate-y: 0px; --tw-translate-y: 0px;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@ -2974,6 +3009,10 @@ input:checked + .toggle-bg {
--tw-shadow: var(--tw-shadow-colored); --tw-shadow: var(--tw-shadow-colored);
} }
:is(.dark .dark\:ring-offset-gray-800) {
--tw-ring-offset-color: #1F2937;
}
:is(.dark .dark\:hover\:border-gray-600:hover) { :is(.dark .dark\:hover\:border-gray-600:hover) {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity)); border-color: rgb(75 85 99 / var(--tw-border-opacity));
@ -3099,11 +3138,25 @@ input:checked + .toggle-bg {
--tw-ring-color: rgb(5 80 92 / var(--tw-ring-opacity)); --tw-ring-color: rgb(5 80 92 / var(--tw-ring-opacity));
} }
:is(.dark .dark\:focus\:ring-blue-600:focus) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(28 100 242 / var(--tw-ring-opacity));
}
:is(.dark .dark\:focus\:ring-offset-gray-800:focus) {
--tw-ring-offset-color: #1F2937;
}
:is(.dark .group:hover .dark\:group-hover\:text-white) { :is(.dark .group:hover .dark\:group-hover\:text-white) {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
:is(.dark .group:hover .dark\:group-hover\:text-gray-300) {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
}
.peer:focus ~ :is(.dark .peer-focus\:dark\:text-blue-500) { .peer:focus ~ :is(.dark .peer-focus\:dark\:text-blue-500) {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(63 131 248 / var(--tw-text-opacity)); color: rgb(63 131 248 / var(--tw-text-opacity));

File diff suppressed because one or more lines are too long

View File

@ -1,124 +0,0 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">Search results</h1>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Search result for {{query}} </p>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Showing 35 results </p>
<!-- prettier-ignore -->
<ul class="flex md:flex-wrap -mb-px text-xs md:text-sm font-medium text-center" id="myTab" data-tabs-toggle="#myTabContent" role="tablist">
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 rounded-t-lg" id="interpretations-tab" data-tabs-target="#interpretations" type="button" role="tab" aria-controls="interpretations" aria-selected="false"> <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-3"> <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>
Interpretations
</button>
</li>
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="books-tab" data-tabs-target="#books" type="button" role="tab" aria-controls="books" aria-selected="false"> <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-3"> <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>
Books
</button>
</li>
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="users-tab" data-tabs-target="#users" type="button" role="tab" aria-controls="users" aria-selected="false"> <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-3"> <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>
Users
</button>
</li>
<li class="mr-2 w-full md:w-auto" role="presentation">
<!-- prettier-ignore -->
<button class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="tags-tab" data-tabs-target="#tags" type="button" role="tab" aria-controls="tags" aria-selected="false"> <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-3"> <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>
Tags
</button>
</li>
</ul>
</div>
<div id="myTabContent" class="md:mr-64">
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="interpretations" role="tabpanel" aria-labelledby="interpretations-tab">
{% for interpretation in interpretations %}
<!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<div class="flex flex-row pb-3 p-3 w-2/3 md:w-10/12">
<div class="vote-block flex flex-col m-5 justify-center items-center">
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="true">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote %}
stroke-green-500
{% endif %}
" 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="M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18" /> </svg>
</div>
{% endif %}
<span
class="vote-count text-3xl select-none
{% if interpretation.vote_count < 0 %}
text-red-500
{% elif interpretation.vote_count > 0 %}
text-green-500
{% endif %}
"
>
{{ interpretation.vote_count }}
</span>
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="false">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote == False %}
stroke-red-500
{% endif %}
" 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="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3" /> </svg>
</div>
{% endif %}
</div>
<!-- prettier-ignore -->
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
<div class="ql-snow truncate md:max-w-xl">
{% set local_breadcrumbs = interpretation.section.breadcrumbs_path %}
{% include 'book/local_breadcrumbs_navigation.html'%}
<p>{{ interpretation.section.label }}</p>
</a>
<div class="dark:text-white h-30 ql-editor-readonly">
<p>{{ interpretation.text|safe }}</p>
</div>
</div>
<div class="flex mt-auto align-center justify-between md:w-full">
<div>
<span class="hidden md:inline-block">Interpretation by</span>
<a href="{{url_for('user.profile',user_id=interpretation.user.id)}}" class=" text-blue-500 {% if interpretation.user.is_deleted %}line-through{% endif %}">{{interpretation.user.username}}</a> on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div>
<div class="flex ml-auto justify-between w-24">
<button data-tooltip-target="tooltip-click" data-tooltip-trigger="click" id="copyLinkButton" type="button" class="hover:text-white focus:ring-2 rounded-full font-medium text-sm p-2.5 text-center inline-flex items-center dark:hover:text-white" data-link="{{ build_qa_url(interpretation) }}">
<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"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15m0-3l-3-3m0 0l-3 3m3-3V15" /> </svg>
</button>
<div id="tooltip-click" role="tooltip" class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700"> Link copied! <div class="tooltip-arrow" data-popper-arrow></div> </div>
<div class="space-x-0.5 flex items-center">
<a class="!cursor-pointer text-no-underline flex items-center" href="{{ build_qa_url(interpretation) }}" >
<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"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" /> </svg>
<p>{{interpretation.active_comments | length}}</p>
</a>
</div>
</div>
</div>
</dt>
</div>
</dl>
{% endfor %}
</div>
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="books" role="tabpanel" aria-labelledby="books-tab">
</div>
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="users" role="tabpanel" aria-labelledby="users-tab">
</div>
<!-- prettier-ignore -->
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="tags" role="tabpanel" aria-labelledby="tags-tab">
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,49 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">Search results</h1>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Search result for {{query}} </p>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Showing {{count}} results </p>
<!-- prettier-ignore -->
<div class="border-b border-gray-200 dark:border-gray-700">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
<li class="mr-2">
<a href="{{url_for('search.search_interpretations',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group" >
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" 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" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" > <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>
Interpretations
</a>
</li>
<li class="mr-2">
<a class="inline-flex p-4 text-blue-600 border-b-2 border-blue-600 rounded-t-lg active dark:text-blue-500 dark:border-blue-500 group" aria-current="page">
<svg aria-hidden="true" class="w-5 h-5 mr-2 text-blue-600 dark:text-blue-500" 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>
Books
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_users', q=query) }}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Users
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_tags',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Tags
</a>
</li>
</ul>
</div>
</div>
<!-- prettier-ignore -->
<div class="md:mr-64 p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="books" role="tabpanel" aria-labelledby="books-tab">
{% if count<1 %}
{% else %}
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">No {{query}} in any book name or included content, try another search query.</h1>
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,119 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">Search results</h1>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Search result for {{query}} </p>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Showing {{count}} results </p>
<!-- prettier-ignore -->
<div class="border-b border-gray-200 dark:border-gray-700">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
<li class="mr-2">
<a class="inline-flex p-4 text-blue-600 border-b-2 border-blue-600 rounded-t-lg active dark:text-blue-500 dark:border-blue-500 group" aria-current="page">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" class="w-5 h-5 mr-2 text-blue-600 dark:text-blue-500"> <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>
Interpretations
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_books',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group" >
<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>
Books
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_users', q=query) }}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Users
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_tags',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Tags
</a>
</li>
</ul>
</div>
</div>
<!-- prettier-ignore -->
<div class="md:mr-64 p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="interpretations" role="tabpanel" aria-labelledby="interpretations-tab">
{% if count <1 %}
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">No {{query}} in any interpretation, try another search query.</h1>
{% else %}
{% for interpretation in interpretations %}
<!-- prettier-ignore -->
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
<div class="flex flex-row pb-3 p-3 w-2/3 md:w-10/12">
<div class="vote-block flex flex-col m-5 justify-center items-center">
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="true">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote %}
stroke-green-500
{% endif %}
" 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="M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18" /> </svg>
</div>
{% endif %}
<span
class="vote-count text-3xl select-none
{% if interpretation.vote_count < 0 %}
text-red-500
{% elif interpretation.vote_count > 0 %}
text-green-500
{% endif %}
"
>
{{ interpretation.vote_count }}
</span>
{% if interpretation.user_id != current_user.id %}
<div class="vote-button cursor-pointer" data-vote-for="interpretation" data-entity-id="{{ interpretation.id }}" data-positive="false">
<svg class="w-6 h-6 select-none
{% if interpretation.current_user_vote == False %}
stroke-red-500
{% endif %}
" 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="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3" /> </svg>
</div>
{% endif %}
</div>
<!-- prettier-ignore -->
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
<div class="ql-snow md:max-w-xl">
{% set local_breadcrumbs = interpretation.section.breadcrumbs_path %}
{% include 'book/local_breadcrumbs_navigation.html'%}
<p>{{ interpretation.section.label }}</p>
</a>
<div class="dark:text-white h-30 ql-editor-readonly">
<p>{{ interpretation.text|safe }}</p>
</div>
</div>
<div class="flex mt-auto align-center justify-between md:w-full">
<div>
<span class="hidden md:inline-block">Interpretation by</span>
<a href="{{url_for('user.profile',user_id=interpretation.user.id)}}" class=" text-blue-500 {% if interpretation.user.is_deleted %}line-through{% endif %}">{{interpretation.user.username}}</a> on {{interpretation.created_at.strftime('%B %d, %Y')}}
</div>
<div class="flex ml-auto justify-between w-24">
<button data-tooltip-target="tooltip-click" data-tooltip-trigger="click" id="copyLinkButton" type="button" class="hover:text-white focus:ring-2 rounded-full font-medium text-sm p-2.5 text-center inline-flex items-center dark:hover:text-white" data-link="{{ build_qa_url(interpretation) }}">
<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"> <path stroke-linecap="round" stroke-linejoin="round" d="M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15m0-3l-3-3m0 0l-3 3m3-3V15" /> </svg>
</button>
<div id="tooltip-click" role="tooltip" class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700"> Link copied! <div class="tooltip-arrow" data-popper-arrow></div> </div>
<div class="space-x-0.5 flex items-center">
<a class="!cursor-pointer text-no-underline flex items-center" href="{{ build_qa_url(interpretation) }}" >
<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"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" /> </svg>
<p>{{interpretation.active_comments | length}}</p>
</a>
</div>
</div>
</div>
</dt>
</div>
</dl>
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,67 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">Search results</h1>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Search result for {{query}} </p>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Showing {{count}} results </p>
<!-- prettier-ignore -->
<div class="border-b border-gray-200 dark:border-gray-700">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
<li class="mr-2">
<a href="{{url_for('search.search_interpretations',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group" >
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" 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" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" > <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>
Interpretations
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_books',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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>
Books
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_users'q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Users
</a>
</li>
<li class="mr-2">
<a class="inline-flex p-4 text-blue-600 border-b-2 border-blue-600 rounded-t-lg active dark:text-blue-500 dark:border-blue-500 group" aria-current="page">
<svg aria-hidden="true" class="w-5 h-5 mr-2 text-blue-600 dark:text-blue-500" 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>
Tags
</a>
</li>
</ul>
</div>
</div>
<!-- prettier-ignore -->
<div class="md:mr-64 p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="users" role="tabpanel" aria-labelledby="users-tab">
{% if count<1 %}
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">No {{query}} in any user name, try another search query.</h1>
{% else %}
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"> <tr> <th scope="col" class="px-6 py-3">Username</th> <th scope="col" class="px-6 py-3">Action</th> </tr> </thead>
<tbody>
{% for user in users if not user.is_deleted %}
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
<th scope="row" class="flex items-center px-6 py-4 text-gray-900 whitespace-nowrap dark:text-white">
<img class="w-10 h-10 rounded-full" src="data:image/jpeg;base64,{{user.avatar_img}}" alt="User's avatar">
<div class="pl-3">
<div class="text-base font-semibold">{{user.username}}</div>
<div class="font-normal text-gray-500">{{user.wallet_id}}</div>
</div>
</th>
<td class="px-6 py-4">
<a href="{{ url_for('user.profile',user_id=user.id) }}" class="font-medium text-blue-600 dark:text-blue-500 hover:underline">Go to {{user.username}}'s library</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,67 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="border-b border-gray-200 dark:border-gray-700 md:mr-64">
<!-- prettier-ignore -->
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">Search results</h1>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Search result for {{query}} </p>
<!-- prettier-ignore -->
<p class="hidden md:block text-sm ml-4 w-1/2 text-gray-500 text-center md:text-left dark:text-gray-400"> Showing {{count}} results </p>
<!-- prettier-ignore -->
<div class="border-b border-gray-200 dark:border-gray-700">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500 dark:text-gray-400">
<li class="mr-2">
<a href="{{url_for('search.search_interpretations',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group" >
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" 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" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" > <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>
Interpretations
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_books',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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>
Books
</a>
</li>
<li class="mr-2">
<a class="inline-flex p-4 text-blue-600 border-b-2 border-blue-600 rounded-t-lg active dark:text-blue-500 dark:border-blue-500 group" aria-current="page" >
<svg aria-hidden="true" class="w-5 h-5 mr-2 text-blue-600 dark:text-blue-500" 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>
Users
</a>
</li>
<li class="mr-2">
<a href="{{url_for('search.search_tags',q=query)}}" class="inline-flex p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300 group">
<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="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>
Tags
</a>
</li>
</ul>
</div>
</div>
<!-- prettier-ignore -->
<div class="md:mr-64 p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="users" role="tabpanel" aria-labelledby="users-tab">
{% if count<1 %}
<h1 class="hidden md:inline font-extrabold text-lg dark:text-white ml-4 mt-5">No {{query}} in any user name, try another search query.</h1>
{% else %}
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"> <tr> <th scope="col" class="px-6 py-3">Username</th> <th scope="col" class="px-6 py-3">Action</th> </tr> </thead>
<tbody>
{% for user in users if not user.is_deleted %}
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
<th scope="row" class="flex items-center px-6 py-4 text-gray-900 whitespace-nowrap dark:text-white">
<img class="w-10 h-10 rounded-full" src="data:image/jpeg;base64,{{user.avatar_img}}" alt="User's avatar">
<div class="pl-3">
<div class="text-base font-semibold">{{user.username}}</div>
<div class="font-normal text-gray-500">{{user.wallet_id}}</div>
</div>
</th>
<td class="px-6 py-4">
<a href="{{ url_for('user.profile',user_id=user.id) }}" class="font-medium text-blue-600 dark:text-blue-500 hover:underline">Go to {{user.username}}'s library</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endblock %}

View File

@ -2,17 +2,13 @@
<div class="hidden items-center justify-center py-1 bg-white dark:bg-gray-800 md:flex"> <div class="hidden items-center justify-center py-1 bg-white dark:bg-gray-800 md:flex">
<label for="table-search" class="sr-only" >Search</label> <label for="table-search" class="sr-only" >Search</label>
<div class="relative"> <div class="relative">
<form action="{{ url_for('main.search') }}" method="post">
{{ form_hidden_tag() }}
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none"> <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<!-- prettier-ignore --> <!-- prettier-ignore -->
<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> <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> </div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<input id="mainSearchInput" required minlength="1" name="search_query" {% if search_query %}value={{ search_query }}{% endif %} type="text" 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 id="mainSearchInput" required minlength="1" name="search_query" {% if search_query %}value={{ search_query }}{% endif %} type="text" 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> </div>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<button type="submit" id="table-search-user-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="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>
</form>
</div> </div>

View File

@ -8,3 +8,4 @@ from .section import bp as section_blueprint
from .vote import bp as vote_blueprint from .vote import bp as vote_blueprint
from .approve import bp as approve_blueprint from .approve import bp as approve_blueprint
from .star import bp as star_blueprint from .star import bp as star_blueprint
from .search import bp as search_blueprint

View File

@ -6,10 +6,7 @@ from flask import (
) )
from flask_login import login_required, current_user from flask_login import login_required, current_user
from app.controllers import ( from app.controllers import register_book_verify_route, create_breadcrumbs, clean_html
register_book_verify_route,
create_breadcrumbs,
)
from app.controllers.delete_nested_book_entities import ( from app.controllers.delete_nested_book_entities import (
delete_nested_interpretation_entities, delete_nested_interpretation_entities,
) )
@ -122,6 +119,7 @@ def interpretation_create(
if form.validate_on_submit(): if form.validate_on_submit():
interpretation: m.Interpretation = m.Interpretation( interpretation: m.Interpretation = m.Interpretation(
text=form.text.data, text=form.text.data,
plain_text=clean_html(form.text.data),
section_id=section_id, section_id=section_id,
user_id=current_user.id, user_id=current_user.id,
) )
@ -179,6 +177,7 @@ def interpretation_edit(
if form.validate_on_submit(): if form.validate_on_submit():
interpretation.text = form.text.data interpretation.text = form.text.data
interpretation.plain_text = clean_html(form.text.data)
log(log.INFO, "Edit interpretation [%s]", interpretation.id) log(log.INFO, "Edit interpretation [%s]", interpretation.id)
interpretation.save() interpretation.save()

View File

@ -1,6 +1,4 @@
from flask import redirect, url_for, Blueprint, render_template from flask import redirect, url_for, Blueprint
from app import forms as f, models as m
main_blueprint = Blueprint("main", __name__) main_blueprint = Blueprint("main", __name__)
@ -9,32 +7,3 @@ main_blueprint = Blueprint("main", __name__)
@main_blueprint.route("/") @main_blueprint.route("/")
def index(): def index():
return redirect(url_for("home.get_all")) return redirect(url_for("home.get_all"))
@main_blueprint.route("/search", methods=["POST"])
def search():
form = f.SearchForm()
if form.validate_on_submit():
q = form.search_query.data
users = m.User.query.order_by(m.User.id)
if q:
users = users.filter(m.User.username.like(f"%{q}%"))
interpretations = m.Interpretation.query.order_by(m.Interpretation.id)
if q:
interpretations = interpretations.filter(
m.Interpretation.text.like(f"%{q}%")
)
tags = m.Tag.query.order_by(m.Tag.id)
if q:
tags = tags.filter(m.Tag.name.like(f"%{q}%"))
books = m.Book.query.order_by(m.Book.id)
if q:
books = books.filter(m.Book.label.like(f"%{q}%"))
return render_template(
"searchResult.html",
query=q,
users=users,
interpretations=interpretations,
tags=tags,
books=books,
)

76
app/views/search.py Normal file
View File

@ -0,0 +1,76 @@
from flask import Blueprint, render_template, request
from sqlalchemy import func
from app import models as m
bp = Blueprint("search", __name__)
@bp.route("/search_interpretations", methods=["GET"])
def search_interpretations():
q = request.args.get("q", type=str, default="").lower()
interpretations = m.Interpretation.query.order_by(m.Interpretation.id)
if q:
interpretations = interpretations.filter(
(func.lower(m.Interpretation.plain_text).like(f"%{q}%"))
)
count = interpretations.count()
books = m.Book.query.order_by(m.Book.id)
if q:
books = books.filter(m.Book.label.like(f"%{q}%"))
return render_template(
"searchResultsInterpretations.html",
query=q,
interpretations=interpretations,
count=count,
)
@bp.route("/search_books", methods=["GET"])
def search_books():
q = request.args.get("q", type=str, default="")
books = m.Book.query.order_by(m.Book.id)
if q:
books = books.filter((func.lower(m.Book.label).like(f"%{q}%")))
count = books.count()
return render_template(
"searchResultsBooks.html",
query=q,
books=books,
count=count,
)
@bp.route("/search_users", methods=["GET"])
def search_users():
q = request.args.get("q", type=str, default="")
users = m.User.query.order_by(m.User.id)
if q:
users = users.filter(func.lower(m.User.username).like(f"%{q}%"))
count = users.count()
return render_template(
"searchResultsUsers.html",
query=q,
users=users,
count=count,
)
@bp.route("/search_tags", methods=["GET"])
def search_tags():
q = request.args.get("q", type=str, default="")
tags = m.Tag.query.order_by(m.Tag.id)
if q:
tags = tags.filter(func.lower(m.Tag.name).like(f"%{q}%"))
count = tags.count()
return render_template(
"searchResultsUsers.html",
query=q,
tags=tags,
count=count,
)

View File

@ -0,0 +1,32 @@
"""plain_text
Revision ID: a9df3da8cd00
Revises: 883298018384
Create Date: 2023-05-23 10:42:06.239982
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "a9df3da8cd00"
down_revision = "883298018384"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("interpretations", schema=None) as batch_op:
batch_op.add_column(sa.Column("plain_text", sa.Text()))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("interpretations", schema=None) as batch_op:
batch_op.drop_column("plain_text")
# ### end Alembic commands ###

View File

@ -1,18 +1,34 @@
export function slashSearch() { export function slashSearch() {
let firstClick: boolean = true; let firstClick: boolean = true;
const searchBtn: HTMLButtonElement = document.querySelector(
'#global-search-button',
);
const searchInput: HTMLInputElement =
document.querySelector('#mainSearchInput');
window.addEventListener('keypress', e => { window.addEventListener('keypress', e => {
const searchInput: HTMLInputElement =
document.querySelector('#mainSearchInput');
if (e.key === '/' && searchInput) { if (e.key === '/' && searchInput) {
if (firstClick) { if (firstClick) {
e.preventDefault(); e.preventDefault();
firstClick = false; firstClick = false;
} }
console.log(e.key);
searchInput.focus(); searchInput.focus();
} }
searchInput.addEventListener('blur', () => { searchInput.addEventListener('blur', () => {
firstClick = true; firstClick = true;
}); });
}); });
if (searchBtn && searchInput) {
searchBtn.addEventListener('click', async (e: any) => {
e.preventDefault();
const urlParams = new URLSearchParams({
q: searchInput.value,
});
const res = await fetch('/search_interpretations?' + urlParams);
if (res.status === 200) {
window.location.replace(res.url);
} else {
return;
}
});
}
} }