refactore: show sidebar only on chats page, fix width of login and register page, add login button if user is not authenticated

on sidebar
This commit is contained in:
kusowl 2026-05-02 01:15:42 +05:30
parent e134d67cec
commit d57346f3e6
7 changed files with 143 additions and 84 deletions

View File

@ -1,8 +1,7 @@
<div class="flex h-screen w-full">
<div class="flex-1 flex flex-col min-w-0 transition-all duration-300">
<div class="flex-1 flex flex-col min-w-0">
<main class="flex-1 flex items-start justify-center">
<router-outlet></router-outlet>
</main>
</div>
<app-sidebar></app-sidebar>
</div>

View File

@ -1,21 +1,35 @@
<div class="w-full max-w-[450px] mx-auto mt-27 flex flex-col bg-white/5 backdrop-blur-[20px] border border-white/10 rounded-3xl shadow-[0_25px_50px_-12px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.1)] overflow-hidden animate-[slideUpFade_0.8s_cubic-bezier(0.16,1,0.3,1)] p-8">
<div
class="w-90 mx-auto mt-27 flex flex-col bg-white/5 backdrop-blur-[20px] border border-white/10 rounded-3xl shadow-[0_25px_50px_-12px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.1)] overflow-hidden animate-[slideUpFade_0.8s_cubic-bezier(0.16,1,0.3,1)] p-8"
>
<div class="text-center mb-8">
<div class="w-16 h-16 mx-auto mb-4 rounded-full bg-gradient-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-2xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]">
<div
class="w-16 h-16 mx-auto mb-4 rounded-full bg-gradient-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-2xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]"
>
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
></path>
</svg>
</div>
<h1 class="m-0 text-3xl font-semibold tracking-wide bg-gradient-to-r from-white to-indigo-300 bg-clip-text text-transparent">Welcome Back</h1>
<h1
class="m-0 text-3xl font-semibold tracking-wide bg-gradient-to-r from-white to-indigo-300 bg-clip-text text-transparent"
>
Welcome Back
</h1>
<p class="m-0 mt-2 text-sm text-slate-400">Sign in to continue to Post Assistant.</p>
</div>
<app-validation-errors [errors]="allErrors()" />
<form [formGroup]="loginForm" (ngSubmit)="login()" class="flex flex-col gap-5">
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Email</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="email"
@ -27,7 +41,9 @@
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Password</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="password"
@ -48,6 +64,10 @@
<p class="mt-8 text-center text-sm text-slate-400">
Don't have an account?
<a routerLink="/user/register" class="text-[#4facfe] hover:text-[#00f2fe] font-medium transition-colors">Register</a>
<a
routerLink="/user/register"
class="text-[#4facfe] hover:text-[#00f2fe] font-medium transition-colors"
>Register</a
>
</p>
</div>

View File

@ -1,21 +1,35 @@
<div class="w-full max-w-112.5 mx-auto mt-27 flex flex-col bg-white/5 backdrop-blur-[20px] border border-white/10 rounded-3xl shadow-[0_25px_50px_-12px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.1)] overflow-hidden animate-[slideUpFade_0.8s_cubic-bezier(0.16,1,0.3,1)] p-8">
<div
class="w-90 mx-auto mt-27 flex flex-col bg-white/5 backdrop-blur-[20px] border border-white/10 rounded-3xl shadow-[0_25px_50px_-12px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.1)] overflow-hidden animate-[slideUpFade_0.8s_cubic-bezier(0.16,1,0.3,1)] p-8"
>
<div class="text-center mb-8">
<div class="w-16 h-16 mx-auto mb-4 rounded-full bg-linear-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-2xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]">
<div
class="w-16 h-16 mx-auto mb-4 rounded-full bg-linear-to-br from-[#00f2fe] to-[#4facfe] flex items-center justify-center font-semibold text-2xl shadow-[0_0_20px_rgba(79,172,254,0.4)] animate-[pulse_2s_infinite]"
>
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"
></path>
</svg>
</div>
<h1 class="m-0 text-3xl font-semibold tracking-wide bg-linear-to-r from-white to-indigo-300 bg-clip-text text-transparent">Create Account</h1>
<h1
class="m-0 text-3xl font-semibold tracking-wide bg-linear-to-r from-white to-indigo-300 bg-clip-text text-transparent"
>
Create Account
</h1>
<p class="m-0 mt-2 text-sm text-slate-400">Join us and start using Post Assistant.</p>
</div>
<app-validation-errors [errors]="allErrors()" />
<form [formGroup]="registerForm" (ngSubmit)="register()" class="flex flex-col gap-5">
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Name</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="text"
@ -27,7 +41,9 @@
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Email</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="email"
@ -39,7 +55,9 @@
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Password</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="password"
@ -51,7 +69,9 @@
<div class="flex flex-col gap-1.5">
<label class="text-sm font-medium text-slate-300 ml-1">Confirm Password</label>
<div class="flex bg-white/5 px-4 py-3 rounded-xl 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="flex bg-white/5 px-4 py-3 rounded-xl 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 outline-none placeholder-slate-500"
type="password"
@ -71,6 +91,10 @@
<p class="mt-8 text-center text-sm text-slate-400">
Already have an account?
<a routerLink="/user/login" class="text-[#4facfe] hover:text-[#00f2fe] font-medium transition-colors">Sign in</a>
<a
routerLink="/user/login"
class="text-[#4facfe] hover:text-[#00f2fe] font-medium transition-colors"
>Sign in</a
>
</p>
</div>

View File

@ -1,69 +1,72 @@
<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 transition-all duration-300 h-screen">
<div class="h-full flex-1 flex flex-col backdrop-blur-[20px] relative">
<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="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="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'"
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'"
>
{{ msg.attributes.content }}
<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>
</div>
<div class="text-xs text-slate-500 mt-2 px-1">
{{ msg.attributes.createdAt | date:'shortTime' }}
} @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="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"
[formControl]="messageControl"
(keydown.enter)="sendMessage()"
placeholder="Type a message..."
[disabled]="messageStore.isLoading()"
/>
<button
class="bg-linear-to-br from-[#00f2fe] to-[#4facfe] border-none w-8 h-8 rounded-full flex items-center justify-center cursor-pointer text-white transition-all duration-200 hover:scale-105 hover:-translate-y-0.5 hover:shadow-[0_10px_20px_rgba(79,172,254,0.3)] active:scale-95 disabled:hover:scale-100 disabled:hover:translate-y-0 disabled:!bg-none disabled:bg-white/10 disabled:text-white/30 disabled:cursor-not-allowed disabled:transform-none disabled:shadow-none"
(click)="sendMessage()"
[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" />
</svg>
</button>
</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="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"
[formControl]="messageControl"
(keydown.enter)="sendMessage()"
placeholder="Type a message..."
[disabled]="messageStore.isLoading()"
/>
<button
class="bg-linear-to-br from-[#00f2fe] to-[#4facfe] border-none w-8 h-8 rounded-full flex items-center justify-center cursor-pointer text-white transition-all duration-200 hover:scale-105 hover:-translate-y-0.5 hover:shadow-[0_10px_20px_rgba(79,172,254,0.3)] active:scale-95 disabled:hover:scale-100 disabled:hover:translate-y-0 disabled:!bg-none disabled:bg-white/10 disabled:text-white/30 disabled:cursor-not-allowed disabled:transform-none disabled:shadow-none"
(click)="sendMessage()"
[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" />
</svg>
</button>
</div>
</div>
<app-sidebar></app-sidebar>
</div>

View File

@ -3,11 +3,12 @@ import { CommonModule } from '@angular/common';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { ChatStore, MessageStore } from './chat.store';
import { ActivatedRoute } from '@angular/router';
import { Sidebar } from "../core/layout/sidebar/sidebar";
@Component({
selector: 'app-chat',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
imports: [CommonModule, ReactiveFormsModule, Sidebar],
templateUrl: './chat.html',
styleUrl: './chat.css',
})

View File

@ -173,9 +173,10 @@
<!-- Footer -->
<div class="border-t border-[#1e2f4d] px-3 py-3">
<div
class="flex items-center gap-2.5 px-2 py-2 rounded-xl hover:bg-[#111a2e] transition-all duration-150 cursor-pointer group"
>
<div class="flex items-center gap-2.5 transition-all duration-150 group">
@if(authStore.isLoading()) {
<p>Loading...</p>
} @else if(authStore.user() !== null){
<div
class="w-7 h-7 rounded-lg bg-linear-to-br from-[#2d5be3] to-[#1a3a9e] flex items-center justify-center text-white text-xs font-bold shrink-0"
>
@ -205,6 +206,14 @@
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
} @else{
<a
routerLink="/user/login"
class="px-4 py-2 bg-black/9 hover:bg-white/2 hover:ring-1 hover:ring-blue-500 focus:ring-1 focus:ring-blue-500 text-gray-500 text-sm w-full rounded-xl"
>
<span class="text-blue-500 font-bold">Login</span> to save chats
</a>
}
</div>
</div>
</aside>

View File

@ -2,6 +2,7 @@ import { Component, signal, computed, inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ChatStore } from '../../../chat/chat.store';
import { AuthStore } from '../../../auth/auth.store';
@Component({
selector: 'app-sidebar',
@ -12,6 +13,8 @@ import { ChatStore } from '../../../chat/chat.store';
})
export class Sidebar implements OnInit {
protected chatStore = inject(ChatStore);
protected authStore = inject(AuthStore);
protected isOpen = signal(true);
protected searchQuery = signal('');