fix: main chat now fillup space when sidebar is closed.
This commit is contained in:
parent
ad0f0bf67b
commit
e134d67cec
@ -1,5 +1,6 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600&display=swap');
|
||||
|
||||
:host {
|
||||
min-width: 100%;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
@ -36,17 +37,35 @@
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
0%, 80%, 100% { transform: scale(0); opacity: 0.3; }
|
||||
40% { transform: scale(1); opacity: 1; }
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0);
|
||||
opacity: 0.3;
|
||||
}
|
||||
40% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { box-shadow: 0 0 0 0 rgba(79, 172, 254, 0.4); }
|
||||
70% { box-shadow: 0 0 0 10px rgba(79, 172, 254, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(79, 172, 254, 0); }
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(79, 172, 254, 0.4);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 10px rgba(79, 172, 254, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(79, 172, 254, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,39 +1,52 @@
|
||||
<div class="h-screen flex flex-col bg-white/5 backdrop-blur-[20px] border border-white/10 relative">
|
||||
<div class="flex-1 overflow-y-auto p-8 flex flex-col gap-6 scroll-smooth custom-scrollbar" #scrollContainer>
|
||||
<div class="h-screen w-full flex flex-col backdrop-blur-[20px] relative">
|
||||
<div
|
||||
class="flex-1 overflow-y-auto p-8 flex flex-col gap-6 scroll-smooth custom-scrollbar"
|
||||
#scrollContainer
|
||||
>
|
||||
@for (msg of messageStore.messages(); track msg.id) {
|
||||
<div
|
||||
class="flex flex-col max-w-[80%] animate-[messageAppear_0.5s_cubic-bezier(0.16,1,0.3,1)]"
|
||||
[ngClass]="msg.attributes.role === 'user' ? 'self-end items-end' : 'self-start items-start'"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col max-w-[80%] animate-[messageAppear_0.5s_cubic-bezier(0.16,1,0.3,1)]"
|
||||
[ngClass]="msg.attributes.role === 'user' ? 'self-end items-end' : 'self-start items-start'"
|
||||
class="px-5 py-4 rounded-2xl text-sm leading-relaxed shadow-[0_4px_15px_rgba(0,0,0,0.1)] relative whitespace-pre-wrap"
|
||||
[ngClass]="msg.attributes.role === 'user' ? 'bg-linear-to-br from-indigo-500 to-purple-600 text-white rounded-br-sm' : 'bg-white/10 border border-white/5 text-slate-200 rounded-bl-sm backdrop-blur-md'"
|
||||
>
|
||||
<div
|
||||
class="px-5 py-4 rounded-2xl text-sm leading-relaxed shadow-[0_4px_15px_rgba(0,0,0,0.1)] relative whitespace-pre-wrap"
|
||||
[ngClass]="msg.attributes.role === 'user' ? 'bg-linear-to-br from-indigo-500 to-purple-600 text-white rounded-br-sm' : 'bg-white/10 border border-white/5 text-slate-200 rounded-bl-sm backdrop-blur-md'"
|
||||
>
|
||||
{{ msg.attributes.content }}
|
||||
</div>
|
||||
<div class="text-xs text-slate-500 mt-2 px-1">
|
||||
{{ msg.attributes.createdAt | date:'shortTime' }}
|
||||
</div>
|
||||
{{ msg.attributes.content }}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (messageStore.isLoading()) {
|
||||
<div class="flex items-center gap-1.5 px-5 py-4 bg-white/5 rounded-2xl rounded-bl-sm self-start animate-[fadeIn_0.3s_ease-in-out]">
|
||||
<div class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-[-0.32s]"></div>
|
||||
<div class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-[-0.16s]"></div>
|
||||
<div class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-0"></div>
|
||||
<div class="text-xs text-slate-500 mt-2 px-1">
|
||||
{{ msg.attributes.createdAt | date:'shortTime' }}
|
||||
</div>
|
||||
</div>
|
||||
} @if (messageStore.isLoading()) {
|
||||
<div
|
||||
class="flex items-center gap-1.5 px-5 py-4 bg-white/5 rounded-2xl rounded-bl-sm self-start animate-[fadeIn_0.3s_ease-in-out]"
|
||||
>
|
||||
<div
|
||||
class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-[-0.32s]"
|
||||
></div>
|
||||
<div
|
||||
class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-[-0.16s]"
|
||||
></div>
|
||||
<div
|
||||
class="w-2 h-2 bg-[#4facfe] rounded-full animate-[typing_1.4s_infinite_ease-in-out_both] delay-0"
|
||||
></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="px-8 py-3">
|
||||
@if (errorMessage) {
|
||||
<div class="text-[#ff6b6b] text-sm mb-3 px-4 py-2 bg-[#ff6b6b]/10 rounded-lg border border-[#ff6b6b]/20 animate-[fadeIn_0.3s_ease-in-out]">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<div
|
||||
class="text-[#ff6b6b] text-sm mb-3 px-4 py-2 bg-[#ff6b6b]/10 rounded-lg border border-[#ff6b6b]/20 animate-[fadeIn_0.3s_ease-in-out]"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="w-full flex gap-4 bg-white/5 px-4 py-2 rounded-full border border-white/10 transition-all duration-300 focus-within:bg-white/10 focus-within:border-[#4facfe]/50 focus-within:shadow-[0_0_20px_rgba(79,172,254,0.2)]">
|
||||
<div
|
||||
class="w-full flex gap-4 bg-white/5 px-4 py-2 rounded-full border border-white/10 transition-all duration-300 focus-within:bg-white/10 focus-within:border-[#4facfe]/50 focus-within:shadow-[0_0_20px_rgba(79,172,254,0.2)]"
|
||||
>
|
||||
<input
|
||||
class="flex-1 bg-transparent border-none text-white text-base py-1 px-2 outline-none font-inherit placeholder-slate-500"
|
||||
type="text"
|
||||
@ -48,7 +61,7 @@
|
||||
[disabled]="!messageControl.value || messageStore.isLoading()"
|
||||
>
|
||||
<svg class="w-3 h-3 fill-current" viewBox="0 0 24 24">
|
||||
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
|
||||
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@if(!isOpen()){
|
||||
<button
|
||||
*ngIf="!isOpen()"
|
||||
(click)="toggleSidebar()"
|
||||
class="fixed top-4 right-4 z-50 p-2.5 rounded-xl bg-[#1a2744] border border-[#2a3a5c] text-[#7b9cc4] hover:text-white hover:bg-[#243058] hover:border-[#3d5a8a] transition-all duration-200 shadow-lg"
|
||||
title="Open sidebar"
|
||||
@ -19,29 +19,22 @@
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
}
|
||||
|
||||
<!-- Backdrop (mobile) -->
|
||||
<div
|
||||
*ngIf="isOpen()"
|
||||
class="fixed inset-0 bg-black/40 backdrop-blur-sm z-30 lg:hidden"
|
||||
(click)="toggleSidebar()"
|
||||
></div>
|
||||
|
||||
<aside [class]="sidebarClasses()" style="font-family: 'DM Sans', 'Segoe UI', sans-serif;">
|
||||
<div
|
||||
class="absolute top-0 left-0 right-0 h-px bg-linear-to-r from-transparent via-[#3d6cb5] to-transparent"
|
||||
></div>
|
||||
|
||||
<aside [class]="sidebarClasses()">
|
||||
<div class="flex items-center justify-between px-4 pt-5 pb-4 border-b border-[#1e2f4d]">
|
||||
<div class="flex items-center gap-2.5">
|
||||
<div
|
||||
class="w-8 h-8 rounded-full bg-linear-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]">
|
||||
class="w-8 h-8 rounded-full bg-linear-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]"
|
||||
>
|
||||
AI
|
||||
</div>
|
||||
<div>
|
||||
<h1
|
||||
class="m-0 font-semibold tracking-wide bg-linear-to-r from-white to-indigo-300 bg-clip-text text-transparent">
|
||||
Post Assistant</h1>
|
||||
class="m-0 font-semibold tracking-wide bg-linear-to-r from-white to-indigo-300 bg-clip-text text-transparent"
|
||||
>
|
||||
Post Assistant
|
||||
</h1>
|
||||
<p class="m-0 text-xs text-slate-400">Always online, ready to write.</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -79,12 +72,7 @@
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
New Chat
|
||||
</button>
|
||||
@ -115,80 +103,72 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (chatStore.chats().length !== 0) {
|
||||
<div class="flex-1 overflow-y-auto px-2 pb-4 scrollbar-thin">
|
||||
<!-- Chat Items -->
|
||||
<div class="space-y-0.5">
|
||||
@for (chat of chatStore.chats(); track chat.id) {
|
||||
<button
|
||||
(click)="selectChat(chat)"
|
||||
[class]="chatItemClasses(chat)"
|
||||
>
|
||||
<!-- Active indicator -->
|
||||
<div
|
||||
class="absolute left-0 top-1/2 -translate-y-1/2 w-0.5 h-6 bg-[#2d5be3] rounded-r-full"
|
||||
></div>
|
||||
<button (click)="selectChat(chat)" [class]="chatItemClasses(chat)">
|
||||
<!-- Active indicator -->
|
||||
<div
|
||||
class="absolute left-0 top-1/2 -translate-y-1/2 w-0.5 h-6 bg-[#2d5be3] rounded-r-full"
|
||||
></div>
|
||||
|
||||
<div class="flex items-start gap-2.5 w-full min-w-0">
|
||||
<!-- Icon -->
|
||||
<div [class]="chatIconClasses(chat)">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-3 h-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-3 3-3-3z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Text -->
|
||||
<div class="flex-1 min-w-0 text-left">
|
||||
<p
|
||||
class="text-xs font-medium truncate text-white"
|
||||
>
|
||||
{{ chat.attributes.title }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Time -->
|
||||
<span class="text-[9px] text-[#3a5272] shrink-0 mt-0.5">{{
|
||||
formatTime(chat.attributes.createdAt)
|
||||
}}</span>
|
||||
<div class="flex items-start gap-2.5 w-full min-w-0">
|
||||
<!-- Icon -->
|
||||
<div [class]="chatIconClasses(chat)">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-3 h-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-3 3-3-3z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<!-- Text -->
|
||||
<div class="flex-1 min-w-0 text-left">
|
||||
<p class="text-xs font-medium truncate text-white">{{ chat.attributes.title }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Time -->
|
||||
<span class="text-[9px] text-[#3a5272] shrink-0 mt-0.5"
|
||||
>{{ formatTime(chat.attributes.createdAt) }}</span
|
||||
>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<!-- Empty state -->
|
||||
@if (chatStore.chats().length === 0) {
|
||||
<div
|
||||
class="flex flex-col items-center justify-center py-10 px-4 text-center"
|
||||
>
|
||||
<div class="w-10 h-10 rounded-full bg-[#111a2e] flex items-center justify-center mb-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-[#3a5272]"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-xs text-[#3a5272]">No chats found</p>
|
||||
<div class="flex flex-1 flex-col items-center justify-center py-10 px-4 text-center">
|
||||
<div class="w-10 h-10 rounded-full bg-[#111a2e] flex items-center justify-center mb-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-5 h-5 text-[#3a5272]"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-xs text-[#3a5272]">No chats found</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Footer -->
|
||||
|
||||
@ -17,13 +17,13 @@ export class Sidebar implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.chatStore.fetchChats();
|
||||
console.log(this.chatStore.chats());
|
||||
}
|
||||
|
||||
protected sidebarClasses = computed(() => {
|
||||
const base =
|
||||
'fixed top-0 right-0 h-full w-64 border-l border-[#1e2f4d] flex flex-col z-40 transition-transform duration-300 ease-in-out shadow-2xl shadow-black/40 relative overflow-hidden';
|
||||
return this.isOpen() ? base : base + ' translate-x-full';
|
||||
'rounded-l-xl top-0 right-0 h-full border-l border-[#1e2f4d] flex flex-col transition-all duration-300 ease-in-out shadow-2xl shadow-black/40 overflow-hidden';
|
||||
|
||||
return this.isOpen() ? base + ' w-64' : base + ' w-0 border-none opacity-0';
|
||||
});
|
||||
|
||||
protected chatItemClasses(chat: any): string {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user