Update frontend UI with improved layout and styling
- Enhanced homepage with modern design and better visual hierarchy - Improved login page with centered layout and better UX - Updated admin page with cleaner interface - Refined sidebar navigation and layout components - Updated Tailwind config and global styles - Fixed protected route component
This commit is contained in:
@@ -4,6 +4,9 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||||
<title>Znakovni.hr - Hrvatski znakovni jezik</title>
|
<title>Znakovni.hr - Hrvatski znakovni jezik</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRout
|
|||||||
return (
|
return (
|
||||||
<div className="flex h-screen items-center justify-center">
|
<div className="flex h-screen items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-blue-600 border-t-transparent mx-auto"></div>
|
<div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent mx-auto"></div>
|
||||||
<p className="mt-4 text-slate-600">Loading...</p>
|
<p className="mt-4 text-muted-foreground">Loading...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface LayoutProps {
|
|||||||
|
|
||||||
export function Layout({ children }: LayoutProps) {
|
export function Layout({ children }: LayoutProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-slate-50">
|
<div className="flex h-screen bg-indigo-50">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main className="flex-1 overflow-y-auto">
|
<main className="flex-1 overflow-y-auto">
|
||||||
<div className="container mx-auto p-6 max-w-7xl">
|
<div className="container mx-auto p-6 max-w-7xl">
|
||||||
|
|||||||
@@ -44,10 +44,14 @@ export function Sidebar() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen w-60 flex-col bg-slate-800 text-white">
|
<div className="flex h-screen w-60 flex-col bg-white border-r border-border">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="flex h-16 items-center px-6 border-b border-slate-700">
|
<div className="flex h-16 items-center px-6 border-b border-border">
|
||||||
<h1 className="text-xl font-bold">Znakovni.hr</h1>
|
<h1 className="text-xl font-bold">
|
||||||
|
<span className="text-indigo-600">ZNAKOVNI</span>
|
||||||
|
<span className="text-gray-400">.</span>
|
||||||
|
<span className="text-orange-600">hr</span>
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
@@ -63,8 +67,8 @@ export function Sidebar() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||||
isActive
|
isActive
|
||||||
? 'bg-slate-700 text-white'
|
? 'bg-primary text-primary-foreground'
|
||||||
: 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
: 'text-muted-foreground hover:bg-secondary hover:text-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon className="h-5 w-5" />
|
<item.icon className="h-5 w-5" />
|
||||||
@@ -76,7 +80,7 @@ export function Sidebar() {
|
|||||||
|
|
||||||
{/* Support Section */}
|
{/* Support Section */}
|
||||||
<div className="pt-6">
|
<div className="pt-6">
|
||||||
<h3 className="px-3 text-xs font-semibold uppercase tracking-wider text-slate-400 mb-2">
|
<h3 className="px-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2">
|
||||||
Portal za podršku
|
Portal za podršku
|
||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
@@ -89,8 +93,8 @@ export function Sidebar() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||||
isActive
|
isActive
|
||||||
? 'bg-slate-700 text-white'
|
? 'bg-primary text-primary-foreground'
|
||||||
: 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
: 'text-muted-foreground hover:bg-secondary hover:text-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon className="h-5 w-5" />
|
<item.icon className="h-5 w-5" />
|
||||||
@@ -109,8 +113,8 @@ export function Sidebar() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||||
location.pathname === '/admin'
|
location.pathname === '/admin'
|
||||||
? 'bg-slate-700 text-white'
|
? 'bg-primary text-primary-foreground'
|
||||||
: 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
: 'text-muted-foreground hover:bg-secondary hover:text-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Shield className="h-5 w-5" />
|
<Shield className="h-5 w-5" />
|
||||||
@@ -121,16 +125,16 @@ export function Sidebar() {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* User Section */}
|
{/* User Section */}
|
||||||
<div className="border-t border-slate-700 p-4">
|
<div className="border-t border-border p-4">
|
||||||
{user ? (
|
{user ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="px-3 py-2">
|
<div className="px-3 py-2">
|
||||||
<p className="text-sm font-medium text-white">{user.displayName || user.email}</p>
|
<p className="text-sm font-medium text-foreground">{user.displayName || user.email}</p>
|
||||||
<p className="text-xs text-slate-400">{user.email}</p>
|
<p className="text-xs text-muted-foreground">{user.email}</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleLogout}
|
onClick={handleLogout}
|
||||||
className="flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-slate-300 hover:bg-slate-700 hover:text-white transition-colors"
|
className="flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-secondary hover:text-foreground transition-colors"
|
||||||
>
|
>
|
||||||
<LogOut className="h-5 w-5" />
|
<LogOut className="h-5 w-5" />
|
||||||
Sign out
|
Sign out
|
||||||
@@ -139,7 +143,7 @@ export function Sidebar() {
|
|||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
to="/login"
|
to="/login"
|
||||||
className="flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-slate-300 hover:bg-slate-700 hover:text-white transition-colors"
|
className="flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-secondary hover:text-foreground transition-colors"
|
||||||
>
|
>
|
||||||
Sign in
|
Sign in
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -4,26 +4,38 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
/* Indigo-50 (#eef2ff) - Primary background */
|
||||||
--foreground: 222.2 84% 4.9%;
|
--background: 238 100% 97%;
|
||||||
|
/* Slate-900 (#101828) - Primary text */
|
||||||
|
--foreground: 222 47% 11%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 222.2 84% 4.9%;
|
--card-foreground: 222 47% 11%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 222.2 84% 4.9%;
|
--popover-foreground: 222 47% 11%;
|
||||||
--primary: 222.2 47.4% 11.2%;
|
/* Indigo-600 (#4f39f6) - Primary accent color */
|
||||||
--primary-foreground: 210 40% 98%;
|
--primary: 248 91% 60%;
|
||||||
--secondary: 210 40% 96.1%;
|
--primary-foreground: 0 0% 100%;
|
||||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
/* Indigo-50 (#eef2ff) - Secondary background */
|
||||||
--muted: 210 40% 96.1%;
|
--secondary: 238 100% 97%;
|
||||||
--muted-foreground: 215.4 16.3% 46.9%;
|
--secondary-foreground: 248 91% 60%;
|
||||||
--accent: 210 40% 96.1%;
|
/* Slate-100 (#f4f4f6) - Muted background */
|
||||||
--accent-foreground: 222.2 47.4% 11.2%;
|
--muted: 240 5% 96%;
|
||||||
|
/* Slate-600 (#4a5565) - Secondary text */
|
||||||
|
--muted-foreground: 218 15% 35%;
|
||||||
|
--accent: 238 100% 97%;
|
||||||
|
--accent-foreground: 248 91% 60%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 210 40% 98%;
|
--destructive-foreground: 0 0% 100%;
|
||||||
--border: 214.3 31.8% 91.4%;
|
/* Slate-300 (#d0d5e2) - Borders */
|
||||||
--input: 214.3 31.8% 91.4%;
|
--border: 225 20% 85%;
|
||||||
--ring: 222.2 84% 4.9%;
|
--input: 225 20% 85%;
|
||||||
|
--ring: 248 91% 60%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
|
/* CEFR Level Colors */
|
||||||
|
--cefr-a1-a2: 145 100% 33%; /* Green-600 (#00a63e) */
|
||||||
|
--cefr-b1-b2: 32 100% 51%; /* Orange-500 (#ff8904) */
|
||||||
|
--cefr-c1-c2: 14 100% 57%; /* Red-Orange (#ff5c33) */
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ export function Admin() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<div className="flex items-center justify-center h-64">
|
<div className="flex items-center justify-center h-64">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-blue-600 border-t-transparent mx-auto"></div>
|
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent mx-auto"></div>
|
||||||
<p className="mt-4 text-slate-600">Loading users...</p>
|
<p className="mt-4 text-muted-foreground">Loading users...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
@@ -123,7 +123,7 @@ export function Admin() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h1 className="text-3xl font-bold text-slate-900">User Management</h1>
|
<h1 className="text-3xl font-bold text-foreground">User Management</h1>
|
||||||
<Button onClick={() => setShowCreateForm(true)} disabled={showCreateForm || !!editingUser}>
|
<Button onClick={() => setShowCreateForm(true)} disabled={showCreateForm || !!editingUser}>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Create User
|
Create User
|
||||||
@@ -253,7 +253,7 @@ export function Admin() {
|
|||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||||
user.role === 'ADMIN'
|
user.role === 'ADMIN'
|
||||||
? 'bg-purple-100 text-purple-800'
|
? 'bg-indigo-100 text-indigo-800'
|
||||||
: 'bg-gray-100 text-gray-800'
|
: 'bg-gray-100 text-gray-800'
|
||||||
}`}>
|
}`}>
|
||||||
{user.role}
|
{user.role}
|
||||||
|
|||||||
@@ -9,28 +9,28 @@ function Home() {
|
|||||||
description: 'Browse and search Croatian sign language dictionary',
|
description: 'Browse and search Croatian sign language dictionary',
|
||||||
icon: BookOpen,
|
icon: BookOpen,
|
||||||
href: '/dictionary',
|
href: '/dictionary',
|
||||||
color: 'bg-blue-500',
|
color: 'bg-indigo-600',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Znakopis',
|
name: 'Znakopis',
|
||||||
description: 'Build sentences using sign language',
|
description: 'Build sentences using sign language',
|
||||||
icon: FileText,
|
icon: FileText,
|
||||||
href: '/znakopis',
|
href: '/znakopis',
|
||||||
color: 'bg-green-500',
|
color: 'bg-gray-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Video rečenica',
|
name: 'Video rečenica',
|
||||||
description: 'Watch and learn from video sentences',
|
description: 'Watch and learn from video sentences',
|
||||||
icon: Video,
|
icon: Video,
|
||||||
href: '/video-sentence',
|
href: '/video-sentence',
|
||||||
color: 'bg-purple-500',
|
color: 'bg-orange-600',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Oblak',
|
name: 'Oblak',
|
||||||
description: 'Save and manage your documents in the cloud',
|
description: 'Save and manage your documents in the cloud',
|
||||||
icon: Cloud,
|
icon: Cloud,
|
||||||
href: '/cloud',
|
href: '/cloud',
|
||||||
color: 'bg-orange-500',
|
color: 'bg-indigo-600',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -38,10 +38,10 @@ function Home() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1 className="text-4xl font-bold text-slate-900 mb-4">
|
<h1 className="text-4xl font-bold text-foreground mb-4">
|
||||||
Dobrodošli na Znakovni.hr
|
Tvoj put u svijet znakovnog jezika
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-slate-600">
|
<p className="text-lg text-muted-foreground">
|
||||||
Hrvatski znakovni jezik - platforma za učenje i komunikaciju
|
Hrvatski znakovni jezik - platforma za učenje i komunikaciju
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,10 +58,10 @@ function Home() {
|
|||||||
<feature.icon className="h-8 w-8 text-white" />
|
<feature.icon className="h-8 w-8 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-xl font-semibold text-slate-900">
|
<h3 className="text-xl font-semibold text-foreground">
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-slate-600 mt-1">{feature.description}</p>
|
<p className="text-muted-foreground mt-1">{feature.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -25,12 +25,16 @@ export function Login() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen items-center justify-center bg-slate-50">
|
<div className="flex min-h-screen items-center justify-center bg-background">
|
||||||
<div className="w-full max-w-md space-y-8 rounded-lg bg-white p-8 shadow-lg">
|
<div className="w-full max-w-md space-y-8 rounded-lg bg-card p-8 shadow-lg">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1 className="text-3xl font-bold text-slate-900">Znakovni.hr</h1>
|
<h1 className="text-3xl font-bold">
|
||||||
<p className="mt-2 text-sm text-slate-600">
|
<span className="text-indigo-600">ZNAKOVNI</span>
|
||||||
|
<span className="text-gray-400">.</span>
|
||||||
|
<span className="text-orange-600">hr</span>
|
||||||
|
</h1>
|
||||||
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
Hrvatski znakovni jezik
|
Hrvatski znakovni jezik
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -83,7 +87,7 @@ export function Login() {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Demo Credentials */}
|
{/* Demo Credentials */}
|
||||||
<div className="mt-4 rounded-md bg-blue-50 p-4 text-sm text-blue-800">
|
<div className="mt-4 rounded-md bg-indigo-50 p-4 text-sm text-indigo-800">
|
||||||
<p className="font-semibold">Demo Credentials:</p>
|
<p className="font-semibold">Demo Credentials:</p>
|
||||||
<p className="mt-1">Admin: admin@znakovni.hr / admin123</p>
|
<p className="mt-1">Admin: admin@znakovni.hr / admin123</p>
|
||||||
<p>User: demo@znakovni.hr / demo123</p>
|
<p>User: demo@znakovni.hr / demo123</p>
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ export default {
|
|||||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||||
|
},
|
||||||
colors: {
|
colors: {
|
||||||
border: 'hsl(var(--border))',
|
border: 'hsl(var(--border))',
|
||||||
input: 'hsl(var(--input))',
|
input: 'hsl(var(--input))',
|
||||||
@@ -38,6 +41,11 @@ export default {
|
|||||||
DEFAULT: 'hsl(var(--card))',
|
DEFAULT: 'hsl(var(--card))',
|
||||||
foreground: 'hsl(var(--card-foreground))',
|
foreground: 'hsl(var(--card-foreground))',
|
||||||
},
|
},
|
||||||
|
cefr: {
|
||||||
|
'a1-a2': 'hsl(var(--cefr-a1-a2))',
|
||||||
|
'b1-b2': 'hsl(var(--cefr-b1-b2))',
|
||||||
|
'c1-c2': 'hsl(var(--cefr-c1-c2))',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
lg: 'var(--radius)',
|
lg: 'var(--radius)',
|
||||||
|
|||||||
Reference in New Issue
Block a user