fix: main chat now fillup space when sidebar is closed.

This commit is contained in:
kusowl 2026-05-02 00:13:18 +05:30
parent ad0f0bf67b
commit e134d67cec
4 changed files with 133 additions and 121 deletions

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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 -->

View File

@ -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 {