Init v1.0.0
Some checks failed
Build & Push Docker Image / build (push) Failing after 53s

This commit is contained in:
2026-02-24 18:14:16 +01:00
commit 54d6ee553a
49 changed files with 10410 additions and 0 deletions

118
src/components/Navbar.jsx Normal file
View File

@@ -0,0 +1,118 @@
import { Menu, Search, LogOut, User } from 'lucide-react';
import { useAuth } from '../contexts/AuthContext';
import { useLanguage } from '../contexts/LanguageContext';
import { useNavigate } from 'react-router-dom';
import { useState, useRef, useEffect } from 'react';
import api from '../services/api';
export default function Navbar({ onMenuClick }) {
const { user, logout } = useAuth();
const { t } = useLanguage();
const navigate = useNavigate();
const [dropdownOpen, setDropdownOpen] = useState(false);
const dropdownRef = useRef(null);
useEffect(() => {
function handleClick(e) {
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
setDropdownOpen(false);
}
}
document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, []);
const handleLogout = () => {
logout();
navigate('/');
};
const initials = user?.name
? user.name
.split(' ')
.map(n => n[0])
.join('')
.toUpperCase()
.slice(0, 2)
: '?';
return (
<header className="sticky top-0 z-20 bg-th-nav border-b border-th-border backdrop-blur-sm">
<div className="flex items-center justify-between h-16 px-4 md:px-6">
{/* Left section */}
<div className="flex items-center gap-3">
<button
onClick={onMenuClick}
className="lg:hidden p-2 rounded-lg hover:bg-th-hover text-th-text-s transition-colors"
>
<Menu size={20} />
</button>
{/* Search */}
<div className="hidden md:flex items-center gap-2 bg-th-bg-s border border-th-border rounded-lg px-3 py-2 w-64 lg:w-80">
<Search size={16} className="text-th-text-s flex-shrink-0" />
<input
type="text"
placeholder={t('common.search')}
className="bg-transparent border-none outline-none text-sm text-th-text placeholder-th-text-s w-full"
/>
</div>
</div>
{/* Right section */}
<div className="flex items-center gap-2">
{/* User dropdown */}
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setDropdownOpen(!dropdownOpen)}
className="flex items-center gap-2 p-1.5 rounded-lg hover:bg-th-hover transition-colors"
>
<div
className="w-8 h-8 rounded-full flex items-center justify-center text-white text-xs font-bold overflow-hidden"
style={{ backgroundColor: user?.avatar_color || '#6366f1' }}
>
{user?.avatar_image ? (
<img
src={`${api.defaults.baseURL}/auth/avatar/${user.avatar_image}`}
alt="Avatar"
className="w-full h-full object-cover"
/>
) : (
initials
)}
</div>
<span className="hidden md:block text-sm font-medium text-th-text">
{user?.name}
</span>
</button>
{dropdownOpen && (
<div className="absolute right-0 mt-2 w-56 bg-th-card rounded-xl border border-th-border shadow-th-lg overflow-hidden">
<div className="px-4 py-3 border-b border-th-border">
<p className="text-sm font-medium text-th-text">{user?.name}</p>
<p className="text-xs text-th-text-s">{user?.email}</p>
</div>
<div className="py-1">
<button
onClick={() => { navigate('/settings'); setDropdownOpen(false); }}
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-th-text hover:bg-th-hover transition-colors"
>
<User size={16} />
{t('nav.settings')}
</button>
<button
onClick={handleLogout}
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-th-error hover:bg-th-hover transition-colors"
>
<LogOut size={16} />
{t('auth.logout')}
</button>
</div>
</div>
)}
</div>
</div>
</div>
</header>
);
}