Refactor AI sidebar with enhanced chat menu and interactions
- Update sidebar layout with dynamic width and improved responsiveness - Add new chat menu Stimulus controller for toggling between chat and chat list views - Improve chat list display with recent chats and empty state - Extract AI avatar to a partial for reusability - Enhance message display and interaction styling - Add more contextual buttons and interaction hints
This commit is contained in:
85
app/assets/images/ai.svg
Normal file
85
app/assets/images/ai.svg
Normal file
@@ -0,0 +1,85 @@
|
||||
<svg width="62" height="68" viewBox="0 0 62 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_f_7620_90382)">
|
||||
<path d="M15.0109 27.3668C14.8138 11.2848 17.2087 15.4884 28.5797 15.5133L32.8675 15.5228C44.2383 15.5478 46.7179 11.3549 46.9149 27.4368L46.9891 33.5015C47.1861 49.5834 44.7913 53.0249 33.4205 52.9999L29.1325 52.9906C17.7617 52.9656 15.2823 49.5134 15.0852 33.4315L15.0109 27.3668Z" fill="url(#paint0_linear_7620_90382)" fill-opacity="0.15"/>
|
||||
</g>
|
||||
<g filter="url(#filter1_i_7620_90382)">
|
||||
<rect x="15" y="13" width="32" height="32" rx="10.6667" fill="url(#paint1_linear_7620_90382)"/>
|
||||
<rect x="15" y="13" width="32" height="32" rx="10.6667" fill="white" fill-opacity="0.07" style="mix-blend-mode:plus-lighter"/>
|
||||
</g>
|
||||
<g filter="url(#filter2_ii_7620_90382)">
|
||||
<rect x="16.7773" y="14.7778" width="28.4444" height="28.4444" rx="8.88889" fill="url(#paint2_linear_7620_90382)"/>
|
||||
<path d="M36.1921 22.073C36.6039 22.0652 36.9439 22.3927 36.9517 22.8044C36.9786 24.2352 37.0273 25.6596 37.0958 27.088C37.1155 27.4993 36.7981 27.8487 36.3868 27.8684C35.9755 27.8881 35.6261 27.5707 35.6063 27.1594C35.5372 25.7174 35.488 24.2785 35.4607 22.8325C35.453 22.4208 35.7804 22.0807 36.1921 22.073Z" fill="#141414"/>
|
||||
<path d="M36.1921 22.073C36.6039 22.0652 36.9439 22.3927 36.9517 22.8044C36.9786 24.2352 37.0273 25.6596 37.0958 27.088C37.1155 27.4993 36.7981 27.8487 36.3868 27.8684C35.9755 27.8881 35.6261 27.5707 35.6063 27.1594C35.5372 25.7174 35.488 24.2785 35.4607 22.8325C35.453 22.4208 35.7804 22.0807 36.1921 22.073Z" fill="url(#paint3_linear_7620_90382)"/>
|
||||
<path d="M30.0884 22.7413C30.3247 22.4041 30.2428 21.9392 29.9056 21.7029C29.5684 21.4666 29.1034 21.5484 28.8671 21.8857C28.2555 22.7586 27.6031 23.6183 26.9349 24.4988C26.6795 24.8354 26.4217 25.1751 26.1631 25.5196C26.1629 25.4497 26.1627 25.379 26.1622 25.3074C26.158 24.7 26.1364 24.0511 26.0192 23.3998C25.9463 22.9946 25.5586 22.7251 25.1533 22.7981C24.7481 22.871 24.4787 23.2587 24.5516 23.6639C24.6454 24.185 24.667 24.7297 24.671 25.3176C24.672 25.4628 24.6719 25.6127 24.6718 25.7658C24.6714 26.2118 24.6709 26.6845 24.6985 27.1431C24.7046 27.2459 24.7313 27.3426 24.7744 27.4294C24.0609 28.4557 23.3903 29.5154 22.8297 30.615C22.8221 30.6299 22.8109 30.6511 22.7968 30.6775C22.7112 30.8389 22.5209 31.1974 22.4089 31.5427C22.3452 31.7392 22.2741 32.0229 22.3076 32.3158C22.3255 32.4722 22.3762 32.6577 22.4979 32.8323C22.6242 33.0135 22.7989 33.142 22.9963 33.2166C24.2085 33.6749 25.5494 33.7216 26.818 33.625C27.848 33.5466 28.8878 33.3675 29.8142 33.2078C30.0261 33.1713 30.2321 33.1358 30.4306 33.1028C30.8368 33.0352 31.1113 32.6512 31.0438 32.245C30.9762 31.8388 30.5921 31.5643 30.1859 31.6318C29.9702 31.6677 29.7524 31.7052 29.5328 31.743C28.6101 31.9017 27.6572 32.0656 26.7048 32.1381C25.6662 32.2172 24.6958 32.1801 23.852 31.9317C23.9193 31.7487 24.0152 31.566 24.0967 31.4107C24.1185 31.3691 24.1393 31.3294 24.1582 31.2923C24.909 29.8195 25.8865 28.397 26.9361 26.9776C27.3129 26.4681 27.7032 25.9536 28.0947 25.4375C28.7774 24.5377 29.4637 23.6329 30.0884 22.7413Z" fill="#141414"/>
|
||||
<path d="M30.0884 22.7413C30.3247 22.4041 30.2428 21.9392 29.9056 21.7029C29.5684 21.4666 29.1034 21.5484 28.8671 21.8857C28.2555 22.7586 27.6031 23.6183 26.9349 24.4988C26.6795 24.8354 26.4217 25.1751 26.1631 25.5196C26.1629 25.4497 26.1627 25.379 26.1622 25.3074C26.158 24.7 26.1364 24.0511 26.0192 23.3998C25.9463 22.9946 25.5586 22.7251 25.1533 22.7981C24.7481 22.871 24.4787 23.2587 24.5516 23.6639C24.6454 24.185 24.667 24.7297 24.671 25.3176C24.672 25.4628 24.6719 25.6127 24.6718 25.7658C24.6714 26.2118 24.6709 26.6845 24.6985 27.1431C24.7046 27.2459 24.7313 27.3426 24.7744 27.4294C24.0609 28.4557 23.3903 29.5154 22.8297 30.615C22.8221 30.6299 22.8109 30.6511 22.7968 30.6775C22.7112 30.8389 22.5209 31.1974 22.4089 31.5427C22.3452 31.7392 22.2741 32.0229 22.3076 32.3158C22.3255 32.4722 22.3762 32.6577 22.4979 32.8323C22.6242 33.0135 22.7989 33.142 22.9963 33.2166C24.2085 33.6749 25.5494 33.7216 26.818 33.625C27.848 33.5466 28.8878 33.3675 29.8142 33.2078C30.0261 33.1713 30.2321 33.1358 30.4306 33.1028C30.8368 33.0352 31.1113 32.6512 31.0438 32.245C30.9762 31.8388 30.5921 31.5643 30.1859 31.6318C29.9702 31.6677 29.7524 31.7052 29.5328 31.743C28.6101 31.9017 27.6572 32.0656 26.7048 32.1381C25.6662 32.2172 24.6958 32.1801 23.852 31.9317C23.9193 31.7487 24.0152 31.566 24.0967 31.4107C24.1185 31.3691 24.1393 31.3294 24.1582 31.2923C24.909 29.8195 25.8865 28.397 26.9361 26.9776C27.3129 26.4681 27.7032 25.9536 28.0947 25.4375C28.7774 24.5377 29.4637 23.6329 30.0884 22.7413Z" fill="url(#paint4_linear_7620_90382)"/>
|
||||
<path d="M36.2391 34.7581C36.3664 34.3664 36.1522 33.9458 35.7606 33.8185C35.369 33.6911 34.9483 33.9054 34.821 34.297C34.6438 34.842 34.4106 35.256 34.12 35.541C33.8419 35.8137 33.4787 36.0015 32.9619 36.0499C32.1922 36.1221 31.4116 35.7978 31.071 35.2344C30.858 34.882 30.3996 34.7691 30.0472 34.9821C29.6948 35.1951 29.5818 35.6535 29.7949 36.0059C30.5079 37.1855 31.9259 37.6448 33.1011 37.5346C33.9477 37.4552 34.6338 37.1258 35.1641 36.6056C35.6819 36.0978 36.0163 35.4433 36.2391 34.7581Z" fill="#141414"/>
|
||||
<path d="M36.2391 34.7581C36.3664 34.3664 36.1522 33.9458 35.7606 33.8185C35.369 33.6911 34.9483 33.9054 34.821 34.297C34.6438 34.842 34.4106 35.256 34.12 35.541C33.8419 35.8137 33.4787 36.0015 32.9619 36.0499C32.1922 36.1221 31.4116 35.7978 31.071 35.2344C30.858 34.882 30.3996 34.7691 30.0472 34.9821C29.6948 35.1951 29.5818 35.6535 29.7949 36.0059C30.5079 37.1855 31.9259 37.6448 33.1011 37.5346C33.9477 37.4552 34.6338 37.1258 35.1641 36.6056C35.6819 36.0978 36.0163 35.4433 36.2391 34.7581Z" fill="url(#paint5_linear_7620_90382)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_7620_90382" x="0.937778" y="0.937778" width="60.1244" height="66.1244" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="7.03111" result="effect1_foregroundBlur_7620_90382"/>
|
||||
</filter>
|
||||
<filter id="filter1_i_7620_90382" x="15" y="13" width="32" height="32" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="0.49869"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_7620_90382"/>
|
||||
</filter>
|
||||
<filter id="filter2_ii_7620_90382" x="16.7773" y="13.8889" width="28.4453" height="30.2222" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="-0.888889"/>
|
||||
<feGaussianBlur stdDeviation="0.888889"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.980392 0 0 0 0 0.309804 0 0 0 0 0.67451 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_7620_90382"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="0.888889"/>
|
||||
<feGaussianBlur stdDeviation="0.888889"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.2 0 0 0 0 0.835294 0 0 0 0 1 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="effect1_innerShadow_7620_90382" result="effect2_innerShadow_7620_90382"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_7620_90382" x1="30.1185" y1="16.1417" x2="33.7041" y2="53.1754" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22CCEE"/>
|
||||
<stop offset="0.274483" stop-color="#1570EF"/>
|
||||
<stop offset="0.629793" stop-color="#6927DA"/>
|
||||
<stop offset="1" stop-color="#F23E94"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_7620_90382" x1="31" y1="13" x2="31" y2="45" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22CCEE"/>
|
||||
<stop offset="0.274483" stop-color="#1570EF"/>
|
||||
<stop offset="0.629793" stop-color="#6927DA"/>
|
||||
<stop offset="1" stop-color="#F23E94"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_7620_90382" x1="30.9996" y1="23.6667" x2="30.9996" y2="43.2222" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="0.3" stop-color="#F7F7F7"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_7620_90382" x1="32.5419" y1="21.0645" x2="28.4008" y2="36.5193" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22CCEE"/>
|
||||
<stop offset="0.274483" stop-color="#1570EF"/>
|
||||
<stop offset="0.629793" stop-color="#6927DA"/>
|
||||
<stop offset="1" stop-color="#F23E94"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_7620_90382" x1="32.5419" y1="21.0645" x2="28.4008" y2="36.5193" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22CCEE"/>
|
||||
<stop offset="0.274483" stop-color="#1570EF"/>
|
||||
<stop offset="0.629793" stop-color="#6927DA"/>
|
||||
<stop offset="1" stop-color="#F23E94"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_7620_90382" x1="32.5419" y1="21.0645" x2="28.4008" y2="36.5193" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22CCEE"/>
|
||||
<stop offset="0.274483" stop-color="#1570EF"/>
|
||||
<stop offset="0.629793" stop-color="#6927DA"/>
|
||||
<stop offset="1" stop-color="#F23E94"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
32
app/javascript/controllers/chat_menu_controller.js
Normal file
32
app/javascript/controllers/chat_menu_controller.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Controller } from "@hotwired/stimulus";
|
||||
|
||||
/**
|
||||
* A controller to toggle between chat list and chat content in the sidebar
|
||||
*/
|
||||
export default class extends Controller {
|
||||
static targets = ["button", "content", "defaultContent", "menuIcon", "backIcon", "header", "listHeader"];
|
||||
|
||||
connect() {
|
||||
this.isShowingChatList = false;
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.isShowingChatList = !this.isShowingChatList;
|
||||
|
||||
if (this.isShowingChatList) {
|
||||
this.contentTarget.classList.remove("hidden");
|
||||
this.defaultContentTarget.classList.add("hidden");
|
||||
this.menuIconTarget.classList.add("hidden");
|
||||
this.backIconTarget.classList.remove("hidden");
|
||||
this.headerTarget.classList.add("hidden");
|
||||
this.listHeaderTarget.classList.remove("hidden");
|
||||
} else {
|
||||
this.contentTarget.classList.add("hidden");
|
||||
this.defaultContentTarget.classList.remove("hidden");
|
||||
this.menuIconTarget.classList.remove("hidden");
|
||||
this.backIconTarget.classList.add("hidden");
|
||||
this.headerTarget.classList.remove("hidden");
|
||||
this.listHeaderTarget.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= tag.div class: class_names("py-4 shrink-0 h-full overflow-y-auto transition-all duration-300 border-l border-gray-200", right_sidebar_open ? "w-80" : "w-0"), data: { sidebar_target: "rightPanel" } do %>
|
||||
<%= tag.div class: class_names("py-4 shrink-0 h-full overflow-y-auto transition-all duration-300", right_sidebar_open ? "w-[375px]" : "w-0"), data: { sidebar_target: "rightPanel" } do %>
|
||||
<%= render "layouts/shared/ai_sidebar" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
3
app/views/layouts/shared/_ai_avatar.html.erb
Normal file
3
app/views/layouts/shared/_ai_avatar.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="w-18 h-18 flex-shrink-0 -mr-1 -ml-2 -mt-1">
|
||||
<%= image_tag "ai.svg", alt: "AI", class: "w-full h-full" %>
|
||||
</div>
|
||||
@@ -1,101 +1,182 @@
|
||||
<div class="h-full flex flex-col w-full max-w-md bg-white border-l border-gray-200">
|
||||
<div class="h-full flex flex-col w-full max-w-[375px]" data-controller="chat-menu">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<%= turbo_stream_from @chat %>
|
||||
<% end %>
|
||||
|
||||
<div class="px-4 py-3 border-b border-gray-200 flex items-center justify-between">
|
||||
<button class="p-2 rounded-lg hover:bg-gray-100" data-action="click->sidebar#toggle" data-side="right">
|
||||
<%= icon("menu") %>
|
||||
</button>
|
||||
|
||||
<%= link_to chats_path, class: "py-2 px-4 bg-gray-800 text-white rounded-lg text-sm font-medium" do %>
|
||||
All chats
|
||||
<div class="px-4 py-3 flex items-center justify-between">
|
||||
<% if @chat.present? %>
|
||||
<%= link_to root_path, class: "p-2 rounded-lg hover:bg-gray-100" do %>
|
||||
<%= icon("arrow-left") %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<button class="p-2 rounded-lg hover:bg-gray-100" data-chat-menu-target="button" data-action="chat-menu#toggle">
|
||||
<span data-chat-menu-target="menuIcon"><%= icon("menu") %></span>
|
||||
<span data-chat-menu-target="backIcon" class="hidden"><%= icon("arrow-left") %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<%= button_to chat_path(@chat), method: :delete, class: "p-2 rounded-lg hover:bg-gray-100", data: { turbo_confirm: "Are you sure you want to delete this chat?" } do %>
|
||||
<%= icon("trash-2") %>
|
||||
<div class="flex items-center justify-between flex-grow ml-2">
|
||||
<h2 class="text-lg font-medium" data-chat-menu-target="header">Chat</h2>
|
||||
<h2 class="text-lg font-medium hidden" data-chat-menu-target="listHeader">Recent Chats</h2>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<%= button_to chat_path(@chat), method: :delete, class: "p-2 rounded-lg hover:bg-gray-100", data: { turbo_confirm: "Are you sure you want to delete this chat?" } do %>
|
||||
<%= icon("trash-2") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<button class="p-2 rounded-lg hover:bg-gray-100">
|
||||
<%= icon("more-vertical") %>
|
||||
</button>
|
||||
<button class="p-2 rounded-lg hover:bg-gray-100">
|
||||
<%= icon("more-vertical") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chat-messages" class="flex-grow overflow-y-auto px-4 py-3 space-y-6">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<div id="messages" data-turbo-cache="false">
|
||||
<% messages = @messages&.where(internal: [false, nil]) %>
|
||||
<% if messages.any? %>
|
||||
<% messages.each do |message| %>
|
||||
<div class="flex items-start gap-3 <%= message.user? ? 'justify-end' : '' %> mb-4" id="message_<%= message.id %>">
|
||||
<% unless message.user? %>
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-purple-400 to-pink-500 rounded-full flex items-center justify-center flex-shrink-0 text-white">
|
||||
<%= icon("bot") %>
|
||||
</div>
|
||||
<div id="chat-messages" class="flex-grow overflow-y-auto px-4 py-3 space-y-4">
|
||||
<div data-chat-menu-target="content" class="hidden">
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<%= link_to chats_path, data: { turbo_method: :post }, class: "p-1.5 text-gray-500 hover:text-gray-700 rounded-md" do %>
|
||||
<%= icon("plus") %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if Current.user %>
|
||||
<% chats = Current.user.chats.order(updated_at: :desc).limit(10) %>
|
||||
<% if chats.any? %>
|
||||
<div class="space-y-3">
|
||||
<% chats.each do |chat| %>
|
||||
<%= link_to root_path(chat_id: chat.id), class: "block p-3 bg-white border border-gray-200 rounded-lg hover:bg-gray-50" do %>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1 min-w-0">
|
||||
<h4 class="font-medium text-gray-900 truncate"><%= chat.title %></h4>
|
||||
<% last_message = chat.messages.where(internal: [false, nil]).where.not(role: "system").order(created_at: :desc).first %>
|
||||
<% if last_message&.content.present? %>
|
||||
<p class="text-sm text-gray-500 truncate"><%= last_message.content.truncate(60) %></p>
|
||||
<% else %>
|
||||
<p class="text-sm text-gray-500">No messages</p>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="ml-2 flex-shrink-0">
|
||||
<span class="text-xs text-gray-500"><%= time_ago_in_words(chat.updated_at) %> ago</span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<div class="<%= message.user? ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-800' %> rounded-lg p-4 max-w-[85%]">
|
||||
<p><%= message.content %></p>
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to "View all chats", chats_path, class: "text-sm text-blue-600 hover:text-blue-800" %>
|
||||
</div>
|
||||
|
||||
<% if message.user? %>
|
||||
<div class="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center flex-shrink-0 text-gray-700">
|
||||
<%= Current.user.initials %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-center py-6">
|
||||
<div class="w-12 h-12 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<%= icon("message-square") %>
|
||||
</div>
|
||||
<p class="text-gray-500 mb-3">No chats yet</p>
|
||||
<%= link_to "Start a chat", chats_path, data: { turbo_method: :post }, class: "inline-flex items-center gap-2 py-2 px-4 bg-gray-800 text-white rounded-lg text-sm font-medium" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-3 mt-4">
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-purple-400 to-pink-500 rounded-full flex items-center justify-center flex-shrink-0 text-white">
|
||||
<%= icon("bot") %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-chat-menu-target="defaultContent">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<div id="messages" data-turbo-cache="false">
|
||||
<% messages = @messages&.where(internal: [false, nil]) %>
|
||||
<% if messages.any? %>
|
||||
<% messages.each do |message| %>
|
||||
<div class="flex items-start gap-3 <%= message.user? ? 'justify-end' : '' %> mb-4" id="message_<%= message.id %>">
|
||||
<% unless message.user? %>
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<% end %>
|
||||
|
||||
<div class="<%= message.user? ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-800' %> rounded-lg p-4 max-w-[85%]">
|
||||
<p><%= message.content %></p>
|
||||
</div>
|
||||
|
||||
<% if message.user? %>
|
||||
<div class="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center flex-shrink-0 text-gray-700">
|
||||
<%= Current.user.initials %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-1 mt-4">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="bg-gray-100 rounded-lg p-4 max-w-[85%]">
|
||||
<p class="text-gray-800">Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. How can I assist you today?</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<% if Current.user %>
|
||||
<div class="flex items-start gap-1 mt-4">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="bg-gray-100 rounded-lg p-4 max-w-[85%]">
|
||||
<p class="text-gray-800">Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. How can I assist you today?</p>
|
||||
<p class="text-gray-800">Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-gray-200 px-2 py-1 rounded">/ </span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-1 mt-4">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="bg-gray-100 rounded-lg p-4 max-w-[85%]">
|
||||
<p class="text-gray-800">Hey there! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-gray-200 px-2 py-1 rounded">/ </span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-3 mt-4">
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-purple-400 to-pink-500 rounded-full flex items-center justify-center flex-shrink-0 text-white">
|
||||
<%= icon("bot") %>
|
||||
</div>
|
||||
<div class="bg-gray-100 rounded-lg p-4 max-w-[85%]">
|
||||
<p class="text-gray-800">Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-gray-200 px-2 py-1 rounded">/ </span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div id="thinking" class="hidden flex items-start gap-3">
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-purple-400 to-pink-500 rounded-full flex items-center justify-center flex-shrink-0 text-white">
|
||||
<%= icon("bot") %>
|
||||
</div>
|
||||
<div id="thinking" class="hidden flex items-start gap-1">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="bg-gray-100 rounded-lg p-4 max-w-[85%] flex items-center">
|
||||
<div class="flex gap-1">
|
||||
<div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
|
||||
@@ -107,9 +188,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-3 border-t border-gray-200">
|
||||
<p class="text-xs text-gray-500 text-center mb-2">AI may make mistakes. Make sure to double check responses.</p>
|
||||
|
||||
<div class="px-4 py-3">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<%= form_with model: [@chat, @message], class: "relative", data: { controller: "message-form", action: "turbo:submit-end->message-form#reset" } do |f| %>
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
@@ -179,5 +258,6 @@
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<p class="text-xs text-gray-500 text-center mt-2">AI may make mistakes. Make sure to double check responses.</p>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user