Add AI chat interface to search results page

- Implement AI message container with loading and user interaction states
- Add new SVG icons for AI, send, and stop actions
- Update CSS styles for AI chat interface in LTR and RTL layouts
- Create responsive design for message boxes and loading indicators
- Add placeholder for AI-generated answers with reference link
This commit is contained in:
Gnkalk 2025-02-20 23:12:23 +03:30
parent 9a3d8629e5
commit aa9ea20c0f
6 changed files with 433 additions and 20 deletions

View file

@ -1137,13 +1137,13 @@ main:has(.not-found) .button {
position: relative;
}
#results .results-container .answer-container {
#results .results-container .message-container {
background-color: var(--background-color);
border-radius: 2rem;
padding: 1.5rem;
}
#results .results-container .answer-container .title {
#results .results-container .message-container .title {
align-items: center;
gap: .5rem;
font-size: 1.5rem;
@ -1151,16 +1151,15 @@ main:has(.not-found) .button {
display: flex;
}
#results .results-container .answer-container .title svg {
#results .results-container .message-container .title svg {
fill: var(--primary-color);
}
#results .results-container .answer-container .message-box {
border-radius: 1rem;
#results .results-container .message-container .message-box {
margin-top: 1rem;
}
#results .results-container .answer-container .message-box .message {
#results .results-container .message-container .message-box .message {
background-color: var(--secondary-background-color);
border-radius: 1.5rem 1.5rem 1.5rem .5rem;
width: 80%;
@ -1169,17 +1168,120 @@ main:has(.not-found) .button {
padding: 1rem;
}
#results .results-container .answer-container .message-box .reference {
#results .results-container .message-container .message-box .reference {
color: var(--text-color);
font-size: .8rem;
}
#results .results-container .answer-container .message-box .reference a {
#results .results-container .message-container .message-box .reference a {
background-color: var(--secondary-background-color);
padding: 0 .5rem;
display: inline-block;
}
#results .results-container .message-container .message-box.user {
flex-direction: row-reverse;
display: flex;
}
#results .results-container .message-container .message-box.user .message {
background-color: var(--primary-color);
color: var(--filled-text-color);
border-radius: 1.5rem 1.5rem .5rem;
}
#results .results-container .message-container .load-container {
justify-content: space-between;
align-items: center;
gap: 1rem;
margin-top: 1rem;
display: none;
}
#results .results-container .message-container .load-container .loading-indecators {
background-color: var(--filled-text-color);
border-radius: .5rem 1.5rem 1.5rem;
justify-content: center;
align-items: center;
gap: .5rem;
padding: 1rem;
display: flex;
}
#results .results-container .message-container .load-container .loading-indecators .indecator {
border: 2px solid var(--text-color);
border-radius: 9999px;
width: .6rem;
height: .6rem;
animation: 2s infinite loading-indecator;
}
#results .results-container .message-container .load-container .loading-indecators :nth-child(2) {
animation-delay: 1s;
}
#results .results-container .message-container .load-container .loading-indecators :nth-child(3) {
animation-delay: .5s;
}
#results .results-container .message-container .load-container .btn.stop {
background-color: var(--text-color);
color: var(--filled-text-color);
border-radius: 9999px;
align-items: center;
gap: 1rem;
display: flex;
}
#results .results-container .message-container .send-message {
border: 1px solid var(--border-color);
border-radius: 9999px;
align-items: center;
gap: .5rem;
margin-top: 1rem;
padding: 0 .5rem;
display: flex;
}
#results .results-container .message-container .send-message input {
color: var(--text-color);
background-color: #0000;
border: none;
border-radius: 9999px;
flex: 1;
padding: .5rem;
}
#results .results-container .message-container .send-message input:focus {
outline: none;
}
#results .results-container .message-container .send-message button {
background-color: #0000;
border: none;
}
#results .results-container .message-container .send-message button:focus {
outline: none;
}
#results .results-container .message-container.ai.loading {
background-color: var(--primary-color);
color: var(--filled-text-color);
}
#results .results-container .message-container.ai.loading svg {
fill: var(--filled-text-color);
}
#results .results-container .message-container.ai.loading .load-container {
display: flex;
}
#results .results-container .message-container.ai.loading :is(.message-box, .send-message) {
display: none;
}
#results .results-container .result-group {
background-color: var(--background-color);
border-radius: 2rem;
@ -1618,6 +1720,23 @@ input[type="checkbox"].switch:checked:after {
}
}
@keyframes loading-indecator {
0% {
background-color: #0000;
transform: scale(1);
}
50% {
background-color: #0000;
transform: scale(1);
}
75% {
background-color: var(--text-color);
transform: scale(.9);
}
}
* {
font-family: Inter Variable, sans-serif;
}

View file

@ -1083,13 +1083,13 @@ main:has(.not-found) .button {
position: relative;
}
#results .results-container .answer-container {
#results .results-container .message-container {
background-color: var(--background-color);
border-radius: 2rem;
padding: 1.5rem;
}
#results .results-container .answer-container .title {
#results .results-container .message-container .title {
align-items: center;
gap: .5rem;
font-size: 1.5rem;
@ -1097,16 +1097,15 @@ main:has(.not-found) .button {
display: flex;
}
#results .results-container .answer-container .title svg {
#results .results-container .message-container .title svg {
fill: var(--primary-color);
}
#results .results-container .answer-container .message-box {
border-radius: 1rem;
#results .results-container .message-container .message-box {
margin-top: 1rem;
}
#results .results-container .answer-container .message-box .message {
#results .results-container .message-container .message-box .message {
background-color: var(--secondary-background-color);
border-radius: 1.5rem 1.5rem 1.5rem .5rem;
width: 80%;
@ -1115,17 +1114,120 @@ main:has(.not-found) .button {
padding: 1rem;
}
#results .results-container .answer-container .message-box .reference {
#results .results-container .message-container .message-box .reference {
color: var(--text-color);
font-size: .8rem;
}
#results .results-container .answer-container .message-box .reference a {
#results .results-container .message-container .message-box .reference a {
background-color: var(--secondary-background-color);
padding: 0 .5rem;
display: inline-block;
}
#results .results-container .message-container .message-box.user {
flex-direction: row-reverse;
display: flex;
}
#results .results-container .message-container .message-box.user .message {
background-color: var(--primary-color);
color: var(--filled-text-color);
border-radius: 1.5rem 1.5rem .5rem;
}
#results .results-container .message-container .load-container {
justify-content: space-between;
align-items: center;
gap: 1rem;
margin-top: 1rem;
display: none;
}
#results .results-container .message-container .load-container .loading-indecators {
background-color: var(--filled-text-color);
border-radius: .5rem 1.5rem 1.5rem;
justify-content: center;
align-items: center;
gap: .5rem;
padding: 1rem;
display: flex;
}
#results .results-container .message-container .load-container .loading-indecators .indecator {
border: 2px solid var(--text-color);
border-radius: 9999px;
width: .6rem;
height: .6rem;
animation: 2s infinite loading-indecator;
}
#results .results-container .message-container .load-container .loading-indecators :nth-child(2) {
animation-delay: 1s;
}
#results .results-container .message-container .load-container .loading-indecators :nth-child(3) {
animation-delay: .5s;
}
#results .results-container .message-container .load-container .btn.stop {
background-color: var(--text-color);
color: var(--filled-text-color);
border-radius: 9999px;
align-items: center;
gap: 1rem;
display: flex;
}
#results .results-container .message-container .send-message {
border: 1px solid var(--border-color);
border-radius: 9999px;
align-items: center;
gap: .5rem;
margin-top: 1rem;
padding: 0 .5rem;
display: flex;
}
#results .results-container .message-container .send-message input {
color: var(--text-color);
background-color: #0000;
border: none;
border-radius: 9999px;
flex: 1;
padding: .5rem;
}
#results .results-container .message-container .send-message input:focus {
outline: none;
}
#results .results-container .message-container .send-message button {
background-color: #0000;
border: none;
}
#results .results-container .message-container .send-message button:focus {
outline: none;
}
#results .results-container .message-container.ai.loading {
background-color: var(--primary-color);
color: var(--filled-text-color);
}
#results .results-container .message-container.ai.loading svg {
fill: var(--filled-text-color);
}
#results .results-container .message-container.ai.loading .load-container {
display: flex;
}
#results .results-container .message-container.ai.loading :is(.message-box, .send-message) {
display: none;
}
#results .results-container .result-group {
background-color: var(--background-color);
border-radius: 2rem;
@ -1564,6 +1666,23 @@ input[type="checkbox"].switch:checked:after {
}
}
@keyframes loading-indecator {
0% {
background-color: #0000;
transform: scale(1);
}
50% {
background-color: #0000;
transform: scale(1);
}
75% {
background-color: var(--text-color);
transform: scale(.9);
}
}
* {
font-family: Vazirmatn UI, sans-serif;
}

View file

@ -12,6 +12,9 @@ const svgList = {
info: "node_modules/remixicon/icons/System/information-2-fill.svg",
database: "node_modules/remixicon/icons/Device/database-2-fill.svg",
share: "node_modules/remixicon/icons/System/share-fill.svg",
ai: "node_modules/remixicon/icons/System/apps-2-ai-fill.svg",
send: "node_modules/remixicon/icons/Business/send-plane-2-fill.svg",
stop: "node_modules/remixicon/icons/Media/pause-circle-line.svg",
};
const ejs = require("ejs"),

View file

@ -235,7 +235,7 @@ main:has(.not-found) {
position: relative;
transition: margin-top 100ms ease-in-out;
.answer-container {
.message-container {
background-color: var(--background-color);
padding: 1.5rem;
@include mixin.rounded(lg);
@ -254,7 +254,6 @@ main:has(.not-found) {
.message-box {
margin-top: 1rem;
@include mixin.rounded();
.message {
background-color: var(--secondary-background-color);
@ -275,7 +274,113 @@ main:has(.not-found) {
padding: 0 .5rem;
}
}
&.user {
display: flex;
flex-direction: row-reverse;
.message {
background-color: var(--primary-color);
color: var(--filled-text-color);
border-radius: 1.5rem 1.5rem .5rem 1.5rem;
}
}
}
.load-container {
display: none;
margin-top: 1rem;
justify-content: space-between;
align-items: center;
gap: 1rem;
.loading-indecators {
background-color: var(--filled-text-color);
border-radius: .5rem 1.5rem 1.5rem 1.5rem;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;
gap: .5rem;
.indecator {
width: .6rem;
height: .6rem;
@include mixin.rounded(full);
border: 2px solid var(--text-color);
animation: loading-indecator 2s infinite;
}
:nth-child(2) {
animation-delay: 1s;
}
:nth-child(3) {
animation-delay: .5s;
}
}
.btn.stop {
display: flex;
@include mixin.rounded(full);
gap: 1rem;
align-items: center;
background-color: var(--text-color);
color: var(--filled-text-color);
}
}
.send-message {
display: flex;
border: 1px solid var(--border-color);
@include mixin.rounded(full);
padding: 0 .5rem;
gap: .5rem;
align-items: center;
margin-top: 1rem;
input {
flex: 1;
background-color: transparent;
border: none;
color: var(--text-color);
@include mixin.rounded(full);
padding: .5rem;
&:focus {
outline: none;
}
}
button {
background-color: transparent;
border: none;
&:focus {
outline: none;
}
}
}
&.ai.loading {
background-color: var(--primary-color);
color: var(--filled-text-color);
svg {
fill: var(--filled-text-color);
}
.load-container {
display: flex;
}
:is(.message-box, .send-message) {
display: none;
}
}
}
.result-group {
@ -738,3 +843,20 @@ input[type="checkbox"].switch {
display: none !important;
}
}
@keyframes loading-indecator {
0% {
transform: scale(1);
background-color: transparent;
}
50% {
transform: scale(1);
background-color: transparent;
}
75% {
transform: scale(.9);
background-color: var(--text-color);
}
}

View file

@ -13,6 +13,9 @@
'info':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 9.5C12.8284 9.5 13.5 8.82843 13.5 8C13.5 7.17157 12.8284 6.5 12 6.5C11.1716 6.5 10.5 7.17157 10.5 8C10.5 8.82843 11.1716 9.5 12 9.5ZM14 15H13V10.5H10V12.5H11V15H10V17H14V15Z"/></svg>',
'database':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M21 9.5V12.5C21 14.9853 16.9706 17 12 17C7.02944 17 3 14.9853 3 12.5V9.5C3 11.9853 7.02944 14 12 14C16.9706 14 21 11.9853 21 9.5ZM3 14.5C3 16.9853 7.02944 19 12 19C16.9706 19 21 16.9853 21 14.5V17.5C21 19.9853 16.9706 22 12 22C7.02944 22 3 19.9853 3 17.5V14.5ZM12 12C7.02944 12 3 9.98528 3 7.5C3 5.01472 7.02944 3 12 3C16.9706 3 21 5.01472 21 7.5C21 9.98528 16.9706 12 12 12Z"/></svg>',
'share':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M13.5759 17.2714L8.46576 14.484C7.83312 15.112 6.96187 15.5 6 15.5C4.067 15.5 2.5 13.933 2.5 12C2.5 10.067 4.067 8.5 6 8.5C6.96181 8.5 7.83301 8.88796 8.46564 9.51593L13.5759 6.72855C13.5262 6.49354 13.5 6.24983 13.5 6C13.5 4.067 15.067 2.5 17 2.5C18.933 2.5 20.5 4.067 20.5 6C20.5 7.933 18.933 9.5 17 9.5C16.0381 9.5 15.1669 9.11201 14.5343 8.48399L9.42404 11.2713C9.47382 11.5064 9.5 11.7501 9.5 12C9.5 12.2498 9.47383 12.4935 9.42408 12.7285L14.5343 15.516C15.167 14.888 16.0382 14.5 17 14.5C18.933 14.5 20.5 16.067 20.5 18C20.5 19.933 18.933 21.5 17 21.5C15.067 21.5 13.5 19.933 13.5 18C13.5 17.7502 13.5262 17.5064 13.5759 17.2714Z"/></svg>',
'ai':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M2.5 7C2.5 9.48528 4.51472 11.5 7 11.5C9.48528 11.5 11.5 9.48528 11.5 7C11.5 4.51472 9.48528 2.5 7 2.5C4.51472 2.5 2.5 4.51472 2.5 7ZM2.5 17C2.5 19.4853 4.51472 21.5 7 21.5C9.48528 21.5 11.5 19.4853 11.5 17C11.5 14.5147 9.48528 12.5 7 12.5C4.51472 12.5 2.5 14.5147 2.5 17ZM12.5 17C12.5 19.4853 14.5147 21.5 17 21.5C19.4853 21.5 21.5 19.4853 21.5 17C21.5 14.5147 19.4853 12.5 17 12.5C14.5147 12.5 12.5 14.5147 12.5 17ZM17.5252 11.155L17.8026 10.5186C18.297 9.38398 19.1876 8.48059 20.2988 7.98638L21.1534 7.60631C21.6155 7.4008 21.6155 6.7284 21.1534 6.52289L20.3467 6.16406C19.2068 5.65713 18.3002 4.72031 17.8143 3.54712L17.5295 2.85945C17.3309 2.38018 16.669 2.38018 16.4705 2.85945L16.1856 3.54712C15.6997 4.72031 14.7932 5.65713 13.6534 6.16406L12.8466 6.52289C12.3845 6.7284 12.3845 7.4008 12.8466 7.60631L13.7011 7.98638C14.8124 8.48059 15.7029 9.38398 16.1974 10.5186L16.4748 11.155C16.6778 11.6209 17.3222 11.6209 17.5252 11.155Z"/></svg>',
'send':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M3 12.9999H9V10.9999H3V1.84558C3 1.56944 3.22386 1.34558 3.5 1.34558C3.58425 1.34558 3.66714 1.36687 3.74096 1.40747L22.2034 11.5618C22.4454 11.6949 22.5337 11.9989 22.4006 12.2409C22.3549 12.324 22.2865 12.3924 22.2034 12.4381L3.74096 22.5924C3.499 22.7255 3.19497 22.6372 3.06189 22.3953C3.02129 22.3214 3 22.2386 3 22.1543V12.9999Z"/></svg>',
'stop':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM9 9H11V15H9V9ZM13 9H15V15H13V9Z"/></svg>',
}
-%}

View file

@ -8,8 +8,55 @@ block body %} {% include 'smart/madules/search_header.html' %}
<div
class="results-container {% if results and results|map(attribute='template')|unique|list|count and 'images.html' in results|map(attribute='template')|unique|list %} image-page {% endif %}"
>
<p class="error js-alt">
{{_('Jabir needs JS enabled to work properly.')}}
</p>
<div class="message-container js-only ai loading" id="ai-message-container">
<div class="title">
{{ icon_small('ai') }}
<h3>{{ _('Answer by Jabir') }}</h3>
</div>
<div class="load-container">
<div class="loading-indecators">
<span class="indecator"> </span>
<span class="indecator"> </span>
<span class="indecator"> </span>
</div>
<button class="btn stop">
<span>{{ _('Stop') }}</span> {{ icon_small('stop') }}
</button>
</div>
<div class="user message-box">
<p class="message">{{ q|e }}</p>
</div>
<div class="message-box">
<p class="message">temporary message</p>
<div class="reference">
{{ _('Based on') }}
<a
href=""
{%-
if
results_on_new_tab
%}target="_blank"
rel="noopener noreferrer"
{%-
else
-%}rel="noreferrer"
{%-
endif
-%}
>{{ _('Jabir') }}</a
>
</div>
</div>
<form class="send-message" id="send-message">
<input type="text" placeholder="{{ _('Ask Jabir anything...') }}" />
<button>{{ icon_small('send') }}</button>
</form>
</div>
{% if answers %}
<div class="answer-container">
<div class="message-container">
<div class="title">
{{ icon_small('plugin') }}
<h3>{{ _('Answers by Plugins and Engines') }}</h3>
@ -21,7 +68,7 @@ block body %} {% include 'smart/madules/search_header.html' %}
<p class="message">{{ answer.answer }}</p>
{%- if answer.url -%}
<div class="reference">
Based on
{{ _('Based on') }}
<a
href="{{ answer.url }}"
{%-