From aa9ea20c0fb6a481b8975110a58c32246d7ea504 Mon Sep 17 00:00:00 2001 From: Gnkalk Date: Thu, 20 Feb 2025 23:12:23 +0330 Subject: [PATCH] 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 --- searx/static/themes/smart/css/ltr-style.css | 135 ++++++++++++++++-- searx/static/themes/smart/css/rtl-style.css | 135 ++++++++++++++++-- .../static/themes/smart/scripts/svg2jinja.js | 3 + searx/static/themes/smart/src/scss/style.scss | 126 +++++++++++++++- searx/templates/smart/icons.html | 3 + searx/templates/smart/results.html | 51 ++++++- 6 files changed, 433 insertions(+), 20 deletions(-) diff --git a/searx/static/themes/smart/css/ltr-style.css b/searx/static/themes/smart/css/ltr-style.css index db9abb5a6..b2dfbb63a 100644 --- a/searx/static/themes/smart/css/ltr-style.css +++ b/searx/static/themes/smart/css/ltr-style.css @@ -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; } diff --git a/searx/static/themes/smart/css/rtl-style.css b/searx/static/themes/smart/css/rtl-style.css index 3aee6b3a3..9235643e0 100644 --- a/searx/static/themes/smart/css/rtl-style.css +++ b/searx/static/themes/smart/css/rtl-style.css @@ -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; } diff --git a/searx/static/themes/smart/scripts/svg2jinja.js b/searx/static/themes/smart/scripts/svg2jinja.js index 492d5991b..283f371bd 100644 --- a/searx/static/themes/smart/scripts/svg2jinja.js +++ b/searx/static/themes/smart/scripts/svg2jinja.js @@ -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"), diff --git a/searx/static/themes/smart/src/scss/style.scss b/searx/static/themes/smart/src/scss/style.scss index c1c53c346..c96ea5ad0 100644 --- a/searx/static/themes/smart/src/scss/style.scss +++ b/searx/static/themes/smart/src/scss/style.scss @@ -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 { @@ -737,4 +842,21 @@ input[type="checkbox"].switch { .js-alt { 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); + } } \ No newline at end of file diff --git a/searx/templates/smart/icons.html b/searx/templates/smart/icons.html index db6a77959..fc2a1a801 100644 --- a/searx/templates/smart/icons.html +++ b/searx/templates/smart/icons.html @@ -13,6 +13,9 @@ 'info':'', 'database':'', 'share':'', + 'ai':'', + 'send':'', + 'stop':'', } -%} diff --git a/searx/templates/smart/results.html b/searx/templates/smart/results.html index b74cbf280..fd801d38d 100644 --- a/searx/templates/smart/results.html +++ b/searx/templates/smart/results.html @@ -8,8 +8,55 @@ block body %} {% include 'smart/madules/search_header.html' %}
+

+ {{_('Jabir needs JS enabled to work properly.')}} +

+
+
+ {{ icon_small('ai') }} +

{{ _('Answer by Jabir') }}

+
+
+
+ + + +
+ +
+
+

{{ q|e }}

+
+
+

temporary message

+
+ {{ _('Based on') }} + {{ _('Jabir') }} +
+
+
+ + +
+
{% if answers %} -
+
{{ icon_small('plugin') }}

{{ _('Answers by Plugins and Engines') }}

@@ -21,7 +68,7 @@ block body %} {% include 'smart/madules/search_header.html' %}

{{ answer.answer }}

{%- if answer.url -%}
- Based on + {{ _('Based on') }}