Files
ReadMeABook/documentation/frontend/pages/login.md
kikootwo 50fb5a68af Add custom AI provider support and improve qBittorrent auth
Introduces support for custom OpenAI-compatible AI providers with configurable base URLs, including UI, backend validation, and connection testing. Enhances qBittorrent integration to support HTTP Basic Auth for reverse proxies, adds detailed debug logging, and updates documentation for both features. Also improves login page description logic and AI prompt generation for recommendations.
2026-01-28 11:41:58 -05:00

153 lines
5.1 KiB
Markdown

# Login Page
**Status:** ✅ Implemented | Real floating book covers with professional animations
Stylized entry point with Plex/Audiobookshelf authentication, animated floating popular audiobook covers, and dynamic description based on backend configuration.
## Design
- Full-screen immersive experience with gradient background
- Centered hero with login button
- Animated floating real audiobook covers (popular releases)
- **100 randomly positioned covers** with varied sizes, animations, and depth
- Multi-layer depth effect with z-index layering (0-20)
- Dark theme optimized with glassmorphism card
- Professional streaming service aesthetic
- **Dynamic description** based on backend mode (Plex/Audiobookshelf) and automation status
## Authentication Flow
1. User visits protected route → redirected to `/login`
2. Clicks "Login with Plex"
3. `POST /api/auth/plex/login` → requests PIN
4. Opens Plex OAuth in popup
5. Polls `/api/auth/plex/callback` for authorization
6. User authorizes in Plex popup
7. Callback receives auth token
8. Creates/updates user in DB
9. Returns JWT tokens
10. Client stores tokens in localStorage
11. Redirects to originally requested page or homepage
## Book Covers
**Data Source:** `GET /api/audiobooks/covers`
- Returns up to 200 popular audiobook covers
- Uses cached thumbnails from `audible_cache` table
- Shuffled on each request for variety
- Fallback to placeholder elements if API fails
**Display:**
- **100 covers** shown simultaneously for immersive experience
- Varied sizes: 80-160px wide (1.5 aspect ratio)
- Opacity range: 0.15-0.35 for subtle layering and depth
- Staggered animation delays (0-10s) for natural movement
- Z-index layering (0-20) for depth perception
- Programmatic positioning using seeded random for consistency
- Lazy loading (first 10 eager, rest lazy) for performance
- Hover pauses animation and scales for interaction
**Positioning Algorithm:**
- Seeded random function ensures consistent positions per cover index
- Random distribution across full viewport (0-100% both axes)
- Each cover gets unique: size, position, opacity, delay, z-index, animation type
- Seed multipliers (7, 13, 17, 23, 29, 31) prevent pattern repetition
- Math.sin() based pseudo-random for deterministic results
## Dynamic Description
Description text adapts to backend configuration:
**Plex + Automation Enabled:** "Request audiobooks and they'll automatically download and appear in your Plex library"
**Plex + No Automation:** "Request audiobooks for your Plex library"
**Audiobookshelf + Automation:** "Request audiobooks and they'll automatically download and appear in your Audiobookshelf library"
**Audiobookshelf + No Automation:** "Request audiobooks for your Audiobookshelf library"
**Loading State:** "Your Personal Audiobook Library Manager"
Automation is detected by checking for configured indexer (Prowlarr) via `/api/auth/providers` endpoint.
## State
```typescript
interface LoginPageState {
isLoggingIn: boolean;
error: string | null;
pinId: number | null;
authWindow: Window | null;
bookCovers: BookCover[];
showAdminLogin: boolean;
adminUsername: string;
adminPassword: string;
authProviders: {
backendMode: string;
providers: string[];
registrationEnabled: boolean;
hasLocalUsers: boolean;
oidcProviderName: string | null;
localLoginDisabled: boolean;
automationEnabled: boolean;
} | null;
}
interface BookCover {
asin: string;
title: string;
author: string;
coverUrl: string;
}
```
## Error Handling
**Popup Blocked:** "Popup was blocked. Please allow popups."
**Login Timeout:** 2 min polling timeout
**Plex Unavailable:** "Plex services currently unavailable."
**Covers Fail:** Silent fallback to placeholder gradient elements
## Animations
Three animation speeds with realistic floating motion:
```css
@keyframes float-slow {
/* 22s cycle with 4 keyframes */
0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
25% { transform: translateY(-25px) translateX(15px) rotate(2deg) scale(1.03); }
50% { transform: translateY(-35px) translateX(25px) rotate(4deg) scale(1.05); }
75% { transform: translateY(-20px) translateX(-10px) rotate(-2deg) scale(1.02); }
}
@keyframes float-medium {
/* 16s cycle with 3 keyframes */
0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
33% { transform: translateY(-30px) translateX(-20px) rotate(-3deg) scale(1.04); }
66% { transform: translateY(-15px) translateX(10px) rotate(3deg) scale(1.02); }
}
@keyframes float-fast {
/* 12s cycle with 2 keyframes */
0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
50% { transform: translateY(-28px) translateX(18px) rotate(5deg) scale(1.06); }
}
```
**Features:**
- Scale transformations (1.02-1.06) for depth
- Rotation (-5° to +5°) for natural movement
- X/Y translation for floating effect
- Hover pauses animation
- Shadow-2xl for 3D depth
## Security
- Tokens in localStorage (access 1hr, refresh 7d)
- Tokens cleared on logout
- OAuth state parameter validation
- SameSite cookie attributes
## Tech Stack
- Next.js 14+ Client Component
- Tailwind CSS with custom animations
- Plex OAuth via AuthContext