mirror of
https://gitlab.w-hs.de/an14051/backerup-website.git
synced 2026-07-27 17:35:29 +00:00
feat: implement user authentication and admin management
- Add user management API endpoints for listing and creating users. - Implement login and logout functionality with rate limiting. - Create UI components for login form, logout button, and animated elements. - Add session management with JWT and secure cookie handling. - Seed initial admin user if no users exist. - Introduce utility functions for password hashing and user authentication. - Set up proxy middleware for route protection and security headers. - Create a JSON file for user data storage. - Add links configuration for external resources.
This commit is contained in:
+275
-8
@@ -1,19 +1,286 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #0b0f1a;
|
||||
--foreground: #e2e8f0;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-background: #060810;
|
||||
--color-foreground: #e2e8f0;
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
|
||||
--animate-fade-in: fadeIn 0.8s ease-out both;
|
||||
--animate-slide-up: slideUp 0.8s ease-out both;
|
||||
--animate-glow: glow 3s ease-in-out infinite alternate;
|
||||
--animate-float: float 6s ease-in-out infinite;
|
||||
--animate-gradient: gradientShift 8s ease infinite;
|
||||
--animate-blink: blink 1s step-end infinite;
|
||||
--animate-spin-slow: spinSlow 25s linear infinite;
|
||||
--animate-pulse-slow: pulseSlow 5s ease-in-out infinite;
|
||||
--animate-shimmer: shimmerSlide 3s ease infinite;
|
||||
--animate-scan: scanLine 4s linear infinite;
|
||||
--animate-aurora-1: aurora1 18s ease-in-out infinite alternate;
|
||||
--animate-aurora-2: aurora2 23s ease-in-out infinite alternate-reverse;
|
||||
--animate-aurora-3: aurora3 15s ease-in-out infinite alternate;
|
||||
--animate-border-glow: borderGlow 3s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: #060810;
|
||||
--foreground: #e2e8f0;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from { opacity: 0; transform: translateY(32px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
from {
|
||||
box-shadow: 0 0 20px rgba(6, 182, 212, 0.15), 0 0 40px rgba(6, 182, 212, 0.05);
|
||||
}
|
||||
to {
|
||||
box-shadow: 0 0 40px rgba(6, 182, 212, 0.45), 0 0 80px rgba(6, 182, 212, 0.2), 0 0 120px rgba(6, 182, 212, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
33% { transform: translateY(-14px); }
|
||||
66% { transform: translateY(-7px); }
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes spinSlow {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes pulseSlow {
|
||||
0%, 100% { opacity: 0.12; transform: scale(0.97); }
|
||||
50% { opacity: 0.35; transform: scale(1.03); }
|
||||
}
|
||||
|
||||
@keyframes shimmerSlide {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(200%); }
|
||||
}
|
||||
|
||||
@keyframes scanLine {
|
||||
0% { transform: translateY(-100%); }
|
||||
100% { transform: translateY(500%); }
|
||||
}
|
||||
|
||||
/* ── Glassmorphism ─────────────────────────────────────────── */
|
||||
.glass {
|
||||
background: rgba(255, 255, 255, 0.025);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.glass-heavy {
|
||||
background: rgba(6, 8, 16, 0.85);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
/* ── Gradient text ─────────────────────────────────────────── */
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, #22d3ee 0%, #a78bfa 55%, #22d3ee 100%);
|
||||
background-size: 200% auto;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
animation: gradientShift 8s ease infinite;
|
||||
}
|
||||
|
||||
/* ── Grid background ───────────────────────────────────────── */
|
||||
.grid-bg {
|
||||
background-image:
|
||||
linear-gradient(rgba(6, 182, 212, 0.035) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(6, 182, 212, 0.035) 1px, transparent 1px);
|
||||
background-size: 48px 48px;
|
||||
}
|
||||
|
||||
/* ── Card hover glow ───────────────────────────────────────── */
|
||||
.card-hover {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-3px);
|
||||
border-color: rgba(6, 182, 212, 0.3) !important;
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(6, 182, 212, 0.06),
|
||||
0 16px 48px rgba(0, 0, 0, 0.5),
|
||||
0 0 40px rgba(6, 182, 212, 0.08);
|
||||
}
|
||||
|
||||
/* ── Neon glow border ──────────────────────────────────────── */
|
||||
.neon-cyan {
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(6, 182, 212, 0.5),
|
||||
0 0 16px rgba(6, 182, 212, 0.2);
|
||||
}
|
||||
|
||||
/* ── Shimmer overlay ───────────────────────────────────────── */
|
||||
.shimmer {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.shimmer::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.04), transparent);
|
||||
animation: shimmerSlide 3s ease infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── Terminal scan effect ──────────────────────────────────── */
|
||||
.terminal-scan {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.terminal-scan::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 60px;
|
||||
background: linear-gradient(to bottom, transparent, rgba(6, 182, 212, 0.025), transparent);
|
||||
animation: scanLine 4s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ── Step connector line ───────────────────────────────────── */
|
||||
.step-connector {
|
||||
position: relative;
|
||||
}
|
||||
.step-connector::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: calc(100% + 0px);
|
||||
width: calc(100% - 40px);
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, rgba(6, 182, 212, 0.4), rgba(6, 182, 212, 0.05));
|
||||
}
|
||||
|
||||
/* ── Aurora blob keyframes ────────────────────────────────── */
|
||||
@keyframes aurora1 {
|
||||
0% { transform: translate( 0px, 0px) scale(1.00); }
|
||||
33% { transform: translate( 80px, -70px) scale(1.15); }
|
||||
66% { transform: translate(-50px, 55px) scale(0.90); }
|
||||
100% { transform: translate( 25px, -20px) scale(1.05); }
|
||||
}
|
||||
|
||||
@keyframes aurora2 {
|
||||
0% { transform: translate( 0px, 0px) scale(1.00); }
|
||||
33% { transform: translate(-75px, 65px) scale(0.88); }
|
||||
66% { transform: translate( 90px, -45px) scale(1.12); }
|
||||
100% { transform: translate(-25px, 30px) scale(0.95); }
|
||||
}
|
||||
|
||||
@keyframes aurora3 {
|
||||
0% { transform: translate( 0px, 0px) scale(1.00); }
|
||||
33% { transform: translate( 55px, 75px) scale(1.10); }
|
||||
66% { transform: translate(-65px, -55px) scale(0.92); }
|
||||
100% { transform: translate( 15px, 45px) scale(1.08); }
|
||||
}
|
||||
|
||||
/* ── Border glow pulse ─────────────────────────────────────── */
|
||||
@keyframes borderGlow {
|
||||
from { box-shadow: 0 0 12px rgba(6,182,212,0.3), 0 0 24px rgba(6,182,212,0.1); }
|
||||
to { box-shadow: 0 0 24px rgba(6,182,212,0.6), 0 0 60px rgba(6,182,212,0.25), 0 0 100px rgba(139,92,246,0.1); }
|
||||
}
|
||||
|
||||
/* ── Spotlight card ────────────────────────────────────────── */
|
||||
.spotlight {
|
||||
--mx: -9999px;
|
||||
--my: -9999px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.spotlight::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
background: radial-gradient(
|
||||
280px circle at var(--mx) var(--my),
|
||||
rgba(6, 182, 212, 0.09),
|
||||
transparent 70%
|
||||
);
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s ease;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.spotlight:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.spotlight > * {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ── Nav link underline animation ──────────────────────────── */
|
||||
.nav-link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #22d3ee, #818cf8);
|
||||
transition: width 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.nav-link:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ── Scrollbar ─────────────────────────────────────────────── */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #060810;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
Reference in New Issue
Block a user