Новый стиль
This commit is contained in:
@@ -14,6 +14,10 @@ const translations = {
|
||||
// Profile
|
||||
name: 'Имя',
|
||||
username: 'Имя пользователя',
|
||||
chats: 'Чаты',
|
||||
calls: 'Звонки',
|
||||
contacts: 'Контакты',
|
||||
archive: 'Архив',
|
||||
aboutMe: 'О себе',
|
||||
birthday: 'Дата рождения',
|
||||
enterName: 'Введите имя',
|
||||
@@ -300,6 +304,10 @@ const translations = {
|
||||
tellAboutYourself: 'Tell about yourself',
|
||||
removePhoto: 'Remove photo',
|
||||
language: 'Language',
|
||||
chats: 'Chats',
|
||||
calls: 'Calls',
|
||||
contacts: 'Contacts',
|
||||
archive: 'Archive',
|
||||
interfaceLang: 'Interface language',
|
||||
theme: 'Theme',
|
||||
russian: 'Русский',
|
||||
|
||||
@@ -31,7 +31,7 @@ function AvatarInner({ src, name, size = 'md', className = '', online }: AvatarP
|
||||
const gradientClass = generateAvatarColor(name || '');
|
||||
|
||||
return (
|
||||
<div className={`relative shrink-0 ${className}`}>
|
||||
<div className={`relative shrink-0 ${className} rounded-full border-2 border-outline-variant/10 overflow-hidden`}>
|
||||
{src ? (
|
||||
<img
|
||||
src={src}
|
||||
@@ -40,15 +40,15 @@ function AvatarInner({ src, name, size = 'md', className = '', online }: AvatarP
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className={`${sizeClass} rounded-full bg-gradient-to-br ${gradientClass} flex items-center justify-center text-white font-medium`}
|
||||
className={`${sizeClass} rounded-full bg-gradient-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-bold tracking-tighter`}
|
||||
>
|
||||
{initials}
|
||||
</div>
|
||||
)}
|
||||
{online !== undefined && (
|
||||
<div
|
||||
className={`absolute bottom-0 right-0 ${onlineDotSize[size]} rounded-full border-surface ${
|
||||
online ? 'bg-emerald-500' : 'bg-zinc-500'
|
||||
className={`absolute bottom-0 right-0 ${onlineDotSize[size]} rounded-full border-surface-container ${
|
||||
online ? 'bg-success shadow-[0_0_8px_rgba(76,175,80,0.5)]' : 'bg-on-surface-variant/20'
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { useAuthStore } from '../../../modules/auth/application/authStore';
|
||||
import { useLang } from '../../infrastructure/i18n';
|
||||
|
||||
interface GlobalNavBarProps {
|
||||
activeTab: string;
|
||||
onTabChange: (tab: string) => void;
|
||||
}
|
||||
|
||||
export default function GlobalNavBar({ activeTab, onTabChange }: GlobalNavBarProps) {
|
||||
const { user } = useAuthStore();
|
||||
const { t } = useLang();
|
||||
|
||||
const menuItems = [
|
||||
{ id: 'chats', icon: 'chat', label: t('chats') },
|
||||
{ id: 'calls', icon: 'call', label: t('calls') },
|
||||
{ id: 'contacts', icon: 'contacts', label: t('contacts') },
|
||||
{ id: 'archive', icon: 'archive', label: t('archive') },
|
||||
{ id: 'settings', icon: 'settings', label: t('settings') },
|
||||
];
|
||||
|
||||
return (
|
||||
<nav className="fixed left-0 top-0 h-full z-40 bg-surface-container w-20 flex flex-col items-center py-6 slide-on-ice border-none shadow-xl">
|
||||
<div className="mb-10 flex flex-col items-center">
|
||||
<span className="text-2xl font-black text-primary tracking-tighter italic knot-logo-spin">Knot</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-6 w-full px-2">
|
||||
{menuItems.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => onTabChange(item.id)}
|
||||
className={`flex flex-col items-center justify-center p-3 rounded-xl transition-all duration-300 scale-95 active:scale-90 ${
|
||||
activeTab === item.id
|
||||
? 'bg-primary/10 text-primary'
|
||||
: 'text-on-surface-variant hover:bg-surface-container-high hover:text-primary'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`material-symbols-outlined mb-1 ${activeTab === item.id ? 'fill-1' : ''}`}
|
||||
style={{ fontVariationSettings: `'FILL' ${activeTab === item.id ? 1 : 0}` }}
|
||||
>
|
||||
{item.icon}
|
||||
</span>
|
||||
<span className="text-[10px] font-medium">{item.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-auto group cursor-pointer relative">
|
||||
<div className="absolute -inset-1 bg-primary/20 rounded-full opacity-0 group-hover:opacity-100 blur transition-opacity" />
|
||||
<img
|
||||
alt="User Profile"
|
||||
className="relative w-10 h-10 rounded-full border-2 border-outline-variant/10 hover:border-primary/50 transition-colors object-cover"
|
||||
src={user?.avatar || `https://ui-avatars.com/api/?name=${user?.username || 'user'}&background=3096e5&color=fff`}
|
||||
/>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
@@ -98,59 +98,29 @@ export default function Sidebar() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full h-full flex flex-col bg-surface-secondary sm:rounded-[2rem] overflow-hidden border-x sm:border border-border/50 shadow-2xl relative z-10">
|
||||
{/* Шапка */}
|
||||
<div className="h-14 px-3 flex items-center justify-between border-b border-border/40 bg-surface-secondary flex-shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setShowSideMenu(true)}
|
||||
className="p-1.5 rounded-lg hover:bg-surface-hover transition-colors text-zinc-400 hover:text-white"
|
||||
title={t('menu')}
|
||||
>
|
||||
<Menu size={20} />
|
||||
</button>
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-xl bg-accent text-white flex-shrink-0">
|
||||
<MessageSquare size={16} fill="currentColor" strokeWidth={0} />
|
||||
</div>
|
||||
<h1 className="text-[16px] font-semibold text-white truncate tracking-tight">Knot Messenger</h1>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowNewChat(true)}
|
||||
className="p-1.5 rounded-lg hover:bg-surface-hover transition-colors text-zinc-400 hover:text-white"
|
||||
title={t('newChat')}
|
||||
>
|
||||
<Plus size={22} />
|
||||
</button>
|
||||
<div className="w-full h-full flex flex-col bg-surface-container-low overflow-hidden border-none relative z-10 slide-on-ice">
|
||||
{/* Title Section (Minimal) */}
|
||||
<div className="px-6 py-8 pb-4">
|
||||
<h1 className="text-2xl font-bold font-headline text-white tracking-tight leading-none">{t('chats')}</h1>
|
||||
</div>
|
||||
|
||||
{/* Поиск */}
|
||||
<div className="px-3 py-2 bg-surface-secondary">
|
||||
{/* Search */}
|
||||
<div className="px-6 mb-4">
|
||||
<div className="relative group">
|
||||
<Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-500 transition-colors" />
|
||||
<span className="material-symbols-outlined absolute left-4 top-1/2 -translate-y-1/2 text-on-surface-variant/40 group-focus-within:text-primary transition-colors text-[20px]">search</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('searchChats')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full pl-9 pr-8 py-1.5 rounded-[10px] bg-surface-tertiary text-[14px] text-white placeholder-zinc-500 border border-transparent focus:border-accent/50 hover:bg-surface-hover transition-all outline-none"
|
||||
className="w-full pl-12 pr-4 py-3 rounded-xl bg-surface-container-highest text-sm text-on-surface placeholder-on-surface-variant/30 border-none focus:ring-2 focus:ring-primary/20 hover:bg-surface-bright transition-all outline-none"
|
||||
/>
|
||||
{searchQuery && (
|
||||
<button
|
||||
onClick={() => setSearchQuery('')}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded-full text-zinc-400 hover:text-white transition-colors"
|
||||
title={t('clear')}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Story circles */}
|
||||
{(storyGroups.length > 0 || true) && (
|
||||
<div className="flex items-center gap-2 px-3 py-2 overflow-x-auto scrollbar-hide border-b border-border/20 flex-shrink-0">
|
||||
<div className="flex items-center gap-4 px-6 py-2 pb-6 overflow-x-auto scrollbar-hide flex-shrink-0">
|
||||
{/* Add story circle */}
|
||||
<button
|
||||
onClick={() => setShowCreateStory(true)}
|
||||
@@ -197,10 +167,10 @@ export default function Sidebar() {
|
||||
)}
|
||||
|
||||
{/* Список чатов */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="flex-1 overflow-y-auto px-2 custom-scrollbar">
|
||||
{filteredChats.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-full text-zinc-500 gap-3 px-6">
|
||||
<MessageSquare size={40} className="opacity-30" />
|
||||
<div className="flex flex-col items-center justify-center h-full text-on-surface-variant/40 gap-3 px-6">
|
||||
<span className="material-symbols-outlined text-5xl opacity-20">chat_bubble</span>
|
||||
<p className="text-sm text-center">
|
||||
{searchQuery ? t('nothingFound') : t('noChats')}
|
||||
</p>
|
||||
@@ -211,6 +181,15 @@ export default function Sidebar() {
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Float Action Button equivalent for Web */}
|
||||
<button
|
||||
onClick={() => setShowNewChat(true)}
|
||||
className="absolute bottom-6 right-6 w-14 h-14 rounded-2xl bg-primary text-on-primary-container shadow-lg shadow-primary/20 flex items-center justify-center hover:scale-105 active:scale-95 transition-transform slide-on-ice"
|
||||
title={t('newChat')}
|
||||
>
|
||||
<span className="material-symbols-outlined text-2xl">add</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Модалки */}
|
||||
|
||||
Reference in New Issue
Block a user