This commit is contained in:
Lars Behrends
2026-05-23 00:54:01 +02:00
parent 83617f75e4
commit d61472f069
15 changed files with 281 additions and 283 deletions
+13 -11
View File
@@ -420,7 +420,7 @@ function AppContent() {
}, [location.pathname, searchParams]); }, [location.pathname, searchParams]);
return ( return (
<div className="min-h-screen bg-[#0a0c10] font-sans selection:bg-[#e8466c]/20 selection:text-[#e8466c] flex"> <div className="min-h-screen bg-background font-sans selection:bg-[#e8466c]/20 selection:text-[#e8466c] flex">
<SidebarProvider defaultOpen={true}> <SidebarProvider defaultOpen={true}>
<AppSidebar <AppSidebar
enabledCategories={enabledCategories} enabledCategories={enabledCategories}
@@ -432,7 +432,7 @@ function AppContent() {
<main className="flex-1 flex flex-col relative"> <main className="flex-1 flex flex-col relative">
{/* Header with Search and Add Media */} {/* Header with Search and Add Media */}
<header className="sticky top-0 z-30 bg-[#0a0c10]/80 backdrop-blur-xl border-b border-white/5 px-6 py-4"> <header className="sticky top-0 z-30 bg-background/80 backdrop-blur-xl border-b border-border px-6 py-4">
<div className="flex items-center justify-between gap-4 max-w-[1920px] mx-auto"> <div className="flex items-center justify-between gap-4 max-w-[1920px] mx-auto">
{/* Search Bar */} {/* Search Bar */}
<div className="flex-1 max-w-xl"> <div className="flex-1 max-w-xl">
@@ -443,25 +443,25 @@ function AppContent() {
placeholder="Search library..." placeholder="Search library..."
value={searchQuery} value={searchQuery}
onChange={(e) => handleSearch(e.target.value)} onChange={(e) => handleSearch(e.target.value)}
className="w-full pl-10 pr-4 py-2 bg-[#1a1d26] border-white/10 rounded-lg text-white placeholder:text-gray-500 focus:border-[#e8466c]/50 focus:ring-[#e8466c]/20" className="w-full pl-10 pr-4 py-2 bg-muted/30 border-border rounded-lg text-foreground placeholder:text-muted-foreground focus:border-[#e8466c]/50 focus:ring-[#e8466c]/20"
/> />
</div> </div>
</div> </div>
{/* View Toggle and Add Button */} {/* View Toggle and Add Button */}
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center bg-[#1a1d26] rounded-lg p-1 border border-white/10"> <div className="flex items-center bg-muted/30 rounded-lg p-1 border border-border">
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-8 w-8 rounded bg-white/10 text-white" className="h-8 w-8 rounded bg-accent text-accent-foreground"
> >
<LayoutGrid className="w-4 h-4" /> <LayoutGrid className="w-4 h-4" />
</Button> </Button>
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-8 w-8 rounded text-gray-400 hover:text-white hover:bg-white/5" className="h-8 w-8 rounded text-muted-foreground hover:text-foreground hover:bg-accent"
> >
<List className="w-4 h-4" /> <List className="w-4 h-4" />
</Button> </Button>
@@ -478,6 +478,7 @@ function AppContent() {
</div> </div>
</header> </header>
<div className="flex-1">
<LayoutGroup> <LayoutGroup>
<Routes> <Routes>
<Route path="/" element={ <Route path="/" element={
@@ -542,21 +543,22 @@ function AppContent() {
} /> } />
</Routes> </Routes>
</LayoutGroup> </LayoutGroup>
</div>
{/* Footer */} {/* Footer */}
<footer className="fixed bottom-0 left-64 right-0 py-4 px-6 border-t border-white/5 bg-[#0a0c10] z-40"> <footer className="mt-auto py-3 px-6 border-t border-border bg-background">
<div className="max-w-[1920px] mx-auto flex flex-col md:flex-row items-center justify-between gap-4"> <div className="max-w-[1920px] mx-auto flex flex-col md:flex-row items-center justify-between gap-4">
<div className="flex items-center gap-2 text-sm font-medium text-gray-500"> <div className="flex items-center gap-2 text-sm font-medium text-muted-foreground">
<span>{mediaCounts.all} total</span> <span>{mediaCounts.all} total</span>
<span className="text-gray-700"></span> <span className="text-border-foreground"></span>
<span className="text-blue-400">{mediaCounts.movies} Movies</span> <span className="text-blue-400">{mediaCounts.movies} Movies</span>
<span className="text-green-400">{mediaCounts.series} Series</span> <span className="text-green-400">{mediaCounts.series} Series</span>
<span className="text-purple-400">{mediaCounts.games} Games</span> <span className="text-purple-400">{mediaCounts.games} Games</span>
<span className="text-red-400">{mediaCounts.adult} Adult</span> <span className="text-red-400">{mediaCounts.adult} Adult</span>
<span className="text-gray-700"></span> <span className="text-border-foreground"></span>
<span className="text-[#e8466c]">{mediaCounts.favorites} Favorites</span> <span className="text-[#e8466c]">{mediaCounts.favorites} Favorites</span>
</div> </div>
<p className="text-xs text-gray-600"> <p className="text-xs text-muted-foreground">
© 2026 MediaVault v1.0.0 © 2026 MediaVault v1.0.0
</p> </p>
</div> </div>
+30 -30
View File
@@ -207,7 +207,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<div className="bg-card/50 backdrop-blur-sm rounded-3xl shadow-xl p-8 border border-border/50 max-w-[1600px] mx-auto"> <div className="bg-card/50 backdrop-blur-sm rounded-3xl shadow-xl p-8 border border-border/50 max-w-[1600px] mx-auto">
<div className="flex items-center gap-4 mb-8"> <div className="flex items-center gap-4 mb-8">
<div className="w-14 h-14 rounded-2xl bg-gradient-to-br from-[#6d28d9] to-[#8b5cf6] flex items-center justify-center shadow-lg shadow-[#6d28d9]/30"> <div className="w-14 h-14 rounded-2xl bg-gradient-to-br from-[#e8466c] to-[#f47298] flex items-center justify-center shadow-lg shadow-[#e8466c]/30">
{getCategoryIcon(activeCategory)} {getCategoryIcon(activeCategory)}
</div> </div>
<div> <div>
@@ -234,7 +234,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
{/* Basic Info Card */} {/* Basic Info Card */}
<div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50"> <div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#6d28d9] shadow-sm"> <div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#e8466c] shadow-sm">
<FileText size={16} /> <FileText size={16} />
</div> </div>
<h3 className="text-lg font-black text-foreground">Basic Information</h3> <h3 className="text-lg font-black text-foreground">Basic Information</h3>
@@ -247,7 +247,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.title} value={newMedia.title}
onChange={e => setNewMedia(prev => ({ ...prev, title: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, title: e.target.value }))}
placeholder="e.g. Mob Psycho 100" placeholder="e.g. Mob Psycho 100"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
required required
/> />
</div> </div>
@@ -259,7 +259,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.year} value={newMedia.year}
onChange={e => setNewMedia(prev => ({ ...prev, year: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, year: e.target.value }))}
placeholder="2024" placeholder="2024"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -268,7 +268,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
id="category" id="category"
value={newMedia.category} value={newMedia.category}
onChange={e => setNewMedia(prev => ({ ...prev, category: e.target.value as MediaCategory }))} onChange={e => setNewMedia(prev => ({ ...prev, category: e.target.value as MediaCategory }))}
className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#6d28d9]/50 outline-none" className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#e8466c]/50 outline-none"
> >
{enabledCategories.map(cat => ( {enabledCategories.map(cat => (
<option key={cat} value={cat}>{cat}</option> <option key={cat} value={cat}>{cat}</option>
@@ -283,7 +283,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
id="type" id="type"
value={newMedia.type} value={newMedia.type}
onChange={e => setNewMedia(prev => ({ ...prev, type: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, type: e.target.value }))}
className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#6d28d9]/50 outline-none" className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#e8466c]/50 outline-none"
> >
{newMedia.category === 'Music' ? ( {newMedia.category === 'Music' ? (
<> <>
@@ -322,7 +322,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
id="status" id="status"
value={newMedia.status} value={newMedia.status}
onChange={e => setNewMedia(prev => ({ ...prev, status: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, status: e.target.value }))}
className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#6d28d9]/50 outline-none" className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#e8466c]/50 outline-none"
> >
<option value="Released">Released</option> <option value="Released">Released</option>
<option value="Ongoing">Ongoing</option> <option value="Ongoing">Ongoing</option>
@@ -343,7 +343,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
{/* Media Info Card */} {/* Media Info Card */}
<div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50"> <div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#6d28d9] shadow-sm"> <div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#e8466c] shadow-sm">
<Globe size={16} /> <Globe size={16} />
</div> </div>
<h3 className="text-lg font-black text-foreground">Media Information</h3> <h3 className="text-lg font-black text-foreground">Media Information</h3>
@@ -356,7 +356,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.poster} value={newMedia.poster}
onChange={e => setNewMedia(prev => ({ ...prev, poster: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, poster: e.target.value }))}
placeholder="https://example.com/poster.jpg" placeholder="https://example.com/poster.jpg"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
required required
/> />
</div> </div>
@@ -367,7 +367,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.banner} value={newMedia.banner}
onChange={e => setNewMedia(prev => ({ ...prev, banner: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, banner: e.target.value }))}
placeholder="https://example.com/banner.jpg" placeholder="https://example.com/banner.jpg"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
@@ -377,7 +377,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
id="aspectRatio" id="aspectRatio"
value={newMedia.aspectRatio} value={newMedia.aspectRatio}
onChange={e => setNewMedia(prev => ({ ...prev, aspectRatio: e.target.value as '2/3' | '16/9' | '1/1' }))} onChange={e => setNewMedia(prev => ({ ...prev, aspectRatio: e.target.value as '2/3' | '16/9' | '1/1' }))}
className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#6d28d9]/50 outline-none" className="bg-background border-border/50 rounded-xl h-11 px-3 text-sm font-bold text-foreground focus:ring-2 focus:ring-[#e8466c]/50 outline-none"
> >
<option value="2/3">2:3 (Poster)</option> <option value="2/3">2:3 (Poster)</option>
<option value="16/9">16:9 (Banner)</option> <option value="16/9">16:9 (Banner)</option>
@@ -395,7 +395,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.rating} value={newMedia.rating}
onChange={e => setNewMedia(prev => ({ ...prev, rating: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, rating: e.target.value }))}
placeholder="8.5" placeholder="8.5"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
</div> </div>
@@ -407,7 +407,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
onChange={e => setNewMedia(prev => ({ ...prev, description: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, description: e.target.value }))}
placeholder="Enter a description..." placeholder="Enter a description..."
rows={4} rows={4}
className="bg-background border-border/50 rounded-xl p-3 text-sm focus:ring-2 focus:ring-[#6d28d9]/50 outline-none resize-none" className="bg-background border-border/50 rounded-xl p-3 text-sm focus:ring-2 focus:ring-[#e8466c]/50 outline-none resize-none"
/> />
</div> </div>
</div> </div>
@@ -416,7 +416,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
{(newMedia.category === 'Anime' || newMedia.category === 'Movies' || newMedia.category === 'TV Series' || newMedia.category === 'Adult') && ( {(newMedia.category === 'Anime' || newMedia.category === 'Movies' || newMedia.category === 'TV Series' || newMedia.category === 'Adult') && (
<div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50"> <div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#6d28d9] shadow-sm"> <div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#e8466c] shadow-sm">
<Clock size={16} /> <Clock size={16} />
</div> </div>
<h3 className="text-lg font-black text-foreground">Production Details</h3> <h3 className="text-lg font-black text-foreground">Production Details</h3>
@@ -430,7 +430,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.runtime} value={newMedia.runtime}
onChange={e => setNewMedia(prev => ({ ...prev, runtime: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, runtime: e.target.value }))}
placeholder="120" placeholder="120"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -440,7 +440,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
type="date" type="date"
value={newMedia.releaseDate} value={newMedia.releaseDate}
onChange={e => setNewMedia(prev => ({ ...prev, releaseDate: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, releaseDate: e.target.value }))}
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -450,7 +450,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.director} value={newMedia.director}
onChange={e => setNewMedia(prev => ({ ...prev, director: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, director: e.target.value }))}
placeholder="Director name" placeholder="Director name"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -460,7 +460,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.writer} value={newMedia.writer}
onChange={e => setNewMedia(prev => ({ ...prev, writer: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, writer: e.target.value }))}
placeholder="Writer name" placeholder="Writer name"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
</div> </div>
@@ -469,7 +469,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
{/* Classification Card */} {/* Classification Card */}
<div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50"> <div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#6d28d9] shadow-sm"> <div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#e8466c] shadow-sm">
<Tag size={16} /> <Tag size={16} />
</div> </div>
<h3 className="text-lg font-black text-foreground">Classification</h3> <h3 className="text-lg font-black text-foreground">Classification</h3>
@@ -482,7 +482,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.genres} value={newMedia.genres}
onChange={e => setNewMedia(prev => ({ ...prev, genres: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, genres: e.target.value }))}
placeholder="Action, Drama, Sci-Fi" placeholder="Action, Drama, Sci-Fi"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -492,7 +492,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.tags} value={newMedia.tags}
onChange={e => setNewMedia(prev => ({ ...prev, tags: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, tags: e.target.value }))}
placeholder="Classic, Best-selling" placeholder="Classic, Best-selling"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -502,7 +502,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.studios} value={newMedia.studios}
onChange={e => setNewMedia(prev => ({ ...prev, studios: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, studios: e.target.value }))}
placeholder="Studio A, Studio B" placeholder="Studio A, Studio B"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@@ -512,7 +512,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
value={newMedia.source} value={newMedia.source}
onChange={e => setNewMedia(prev => ({ ...prev, source: e.target.value }))} onChange={e => setNewMedia(prev => ({ ...prev, source: e.target.value }))}
placeholder="e.g. username, xbvr, stashapp" placeholder="e.g. username, xbvr, stashapp"
className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-background border-border/50 rounded-xl h-11 focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
</div> </div>
@@ -522,7 +522,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
{(newMedia.category === 'Anime' || newMedia.category === 'Movies' || newMedia.category === 'TV Series' || newMedia.category === 'Adult') && ( {(newMedia.category === 'Anime' || newMedia.category === 'Movies' || newMedia.category === 'TV Series' || newMedia.category === 'Adult') && (
<div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50 lg:col-span-2"> <div className="bg-muted/30 backdrop-blur-sm rounded-2xl p-6 border border-border/50 lg:col-span-2">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#6d28d9] shadow-sm"> <div className="w-8 h-8 rounded-lg bg-background flex items-center justify-center text-[#e8466c] shadow-sm">
<Users size={16} /> <Users size={16} />
</div> </div>
<h3 className="text-lg font-black text-foreground">Cast & Crew</h3> <h3 className="text-lg font-black text-foreground">Cast & Crew</h3>
@@ -574,7 +574,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<Input <Input
id="staffName" id="staffName"
placeholder="Actor name" placeholder="Actor name"
className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#e8466c]/50"
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault();
@@ -593,7 +593,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<Input <Input
id="staffRole" id="staffRole"
placeholder="e.g. Actor, Director" placeholder="e.g. Actor, Director"
className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#e8466c]/50"
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault();
@@ -611,7 +611,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<Input <Input
id="staffCharacter" id="staffCharacter"
placeholder="Character name" placeholder="Character name"
className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
</div> </div>
@@ -620,14 +620,14 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<Input <Input
id="staffPhoto" id="staffPhoto"
placeholder="https://example.com/photo.jpg" placeholder="https://example.com/photo.jpg"
className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#6d28d9]/50" className="bg-muted/50 border-border/50 rounded-lg h-9 text-sm focus:ring-2 focus:ring-[#e8466c]/50"
/> />
</div> </div>
<Button <Button
type="button" type="button"
onClick={addStaffMember} onClick={addStaffMember}
variant="outline" variant="outline"
className="w-full border-border/50 text-sm font-bold hover:border-[#6d28d9]/50 hover:bg-[#6d28d9]/10 rounded-xl transition-all duration-300" className="w-full border-border/50 text-sm font-bold hover:border-[#e8466c]/50 hover:bg-[#e8466c]/10 rounded-xl transition-all duration-300"
> >
+ Add Cast Member + Add Cast Member
</Button> </Button>
@@ -640,7 +640,7 @@ export default function AddMediaView({ activeCategory, enabledCategories, onAddC
<Button <Button
type="submit" type="submit"
disabled={isSubmitting} disabled={isSubmitting}
className="w-full bg-gradient-to-br from-[#6d28d9] to-[#8b5cf6] hover:from-[#5b21b6] hover:to-[#7c3aed] text-white font-black h-12 rounded-xl shadow-lg shadow-[#6d28d9]/30 transition-all duration-300 hover:scale-[1.02] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100" className="w-full bg-gradient-to-br from-[#e8466c] to-[#f47298] hover:from-[#d13d60] hover:to-[#c5304e] text-white font-black h-12 rounded-xl shadow-lg shadow-[#e8466c]/30 transition-all duration-300 hover:scale-[1.02] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100"
> >
{isSubmitting ? 'SAVING...' : 'SAVE TO LIBRARY'} {isSubmitting ? 'SAVING...' : 'SAVE TO LIBRARY'}
</Button> </Button>
+19 -19
View File
@@ -96,12 +96,12 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
</h1> </h1>
<div className="flex flex-wrap justify-center md:justify-start gap-2"> <div className="flex flex-wrap justify-center md:justify-start gap-2">
{person.occupations?.map(occ => ( {person.occupations?.map(occ => (
<Badge key={occ} variant="secondary" className="bg-[#6d28d9]/10 text-[#6d28d9] border-[#6d28d9]/20 font-medium px-3 py-1 text-xs"> <Badge key={occ} variant="secondary" className="bg-[#e8466c]/10 text-[#e8466c] border-[#e8466c]/20 font-medium px-3 py-1 text-xs">
{occ} {occ}
</Badge> </Badge>
))} ))}
{person.filmography && person.filmography.length > 0 && ( {person.filmography && person.filmography.length > 0 && (
<Badge variant="outline" className="border-[#6d28d9]/30 text-[#6d28d9] font-medium px-3 py-1 text-xs"> <Badge variant="outline" className="border-[#e8466c]/30 text-[#e8466c] font-medium px-3 py-1 text-xs">
<Star className="w-3 h-3 mr-1" /> <Star className="w-3 h-3 mr-1" />
{person.filmography.length} {person.filmography.length}
</Badge> </Badge>
@@ -130,8 +130,8 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
<Card className="border-border/60 overflow-hidden"> <Card className="border-border/60 overflow-hidden">
<CardHeader className="py-3 px-4 border-b border-border/40"> <CardHeader className="py-3 px-4 border-b border-border/40">
<CardTitle className="text-xs font-medium uppercase tracking-wide text-muted-foreground flex items-center gap-2"> <CardTitle className="text-xs font-medium uppercase tracking-wide text-muted-foreground flex items-center gap-2">
<div className="w-5 h-5 rounded bg-[#6d28d9]/10 flex items-center justify-center"> <div className="w-5 h-5 rounded bg-[#e8466c]/10 flex items-center justify-center">
<User size={12} className="text-[#6d28d9]" /> <User size={12} className="text-[#e8466c]" />
</div> </div>
Personal Info Personal Info
</CardTitle> </CardTitle>
@@ -140,7 +140,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{/* Birth Date */} {/* Birth Date */}
<div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="w-7 h-7 rounded-md bg-[#6d28d9]/10 flex items-center justify-center text-[#6d28d9]"> <div className="w-7 h-7 rounded-md bg-[#e8466c]/10 flex items-center justify-center text-[#e8466c]">
<Calendar size={14} /> <Calendar size={14} />
</div> </div>
<span className="text-xs text-muted-foreground">Born</span> <span className="text-xs text-muted-foreground">Born</span>
@@ -152,7 +152,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{/* Birth Place */} {/* Birth Place */}
<div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="w-7 h-7 rounded-md bg-[#6d28d9]/10 flex items-center justify-center text-[#6d28d9]"> <div className="w-7 h-7 rounded-md bg-[#e8466c]/10 flex items-center justify-center text-[#e8466c]">
<MapPin size={14} /> <MapPin size={14} />
</div> </div>
<span className="text-xs text-muted-foreground">Origin</span> <span className="text-xs text-muted-foreground">Origin</span>
@@ -166,12 +166,12 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{/* Known For */} {/* Known For */}
<div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="w-7 h-7 rounded-md bg-[#6d28d9]/10 flex items-center justify-center text-[#6d28d9]"> <div className="w-7 h-7 rounded-md bg-[#e8466c]/10 flex items-center justify-center text-[#e8466c]">
<Briefcase size={14} /> <Briefcase size={14} />
</div> </div>
<span className="text-xs text-muted-foreground">Role</span> <span className="text-xs text-muted-foreground">Role</span>
</div> </div>
<Badge variant="secondary" className="text-xs font-normal bg-[#6d28d9]/10 text-[#6d28d9] border-none"> <Badge variant="secondary" className="text-xs font-normal bg-[#e8466c]/10 text-[#e8466c] border-none">
{person.role} {person.role}
</Badge> </Badge>
</div> </div>
@@ -182,7 +182,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
<Separator /> <Separator />
<div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="flex items-center justify-between px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="w-7 h-7 rounded-md bg-[#6d28d9]/10 flex items-center justify-center text-[#6d28d9]"> <div className="w-7 h-7 rounded-md bg-[#e8466c]/10 flex items-center justify-center text-[#e8466c]">
<User size={14} /> <User size={14} />
</div> </div>
<span className="text-xs text-muted-foreground">Ethnicity</span> <span className="text-xs text-muted-foreground">Ethnicity</span>
@@ -202,8 +202,8 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
<Card className="border-border/60 overflow-hidden"> <Card className="border-border/60 overflow-hidden">
<CardHeader className="py-3 px-4 border-b border-border/40"> <CardHeader className="py-3 px-4 border-b border-border/40">
<CardTitle className="text-xs font-medium uppercase tracking-wide text-muted-foreground flex items-center gap-2"> <CardTitle className="text-xs font-medium uppercase tracking-wide text-muted-foreground flex items-center gap-2">
<div className="w-5 h-5 rounded bg-[#6d28d9]/10 flex items-center justify-center"> <div className="w-5 h-5 rounded bg-[#e8466c]/10 flex items-center justify-center">
<Ruler size={12} className="text-[#6d28d9]" /> <Ruler size={12} className="text-[#e8466c]" />
</div> </div>
Measurements Measurements
</CardTitle> </CardTitle>
@@ -262,7 +262,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{(person.hair_color || person.adult_specifics?.hair_color) && ( {(person.hair_color || person.adult_specifics?.hair_color) && (
<div className="px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2 mb-1"> <div className="flex items-center gap-2 mb-1">
<Palette size={12} className="text-[#6d28d9]" /> <Palette size={12} className="text-[#e8466c]" />
<span className="text-[10px] text-muted-foreground uppercase tracking-wide">Hair</span> <span className="text-[10px] text-muted-foreground uppercase tracking-wide">Hair</span>
</div> </div>
<p className="text-sm font-medium truncate"> <p className="text-sm font-medium truncate">
@@ -273,7 +273,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{(person.eye_color || person.adult_specifics?.eye_color) && ( {(person.eye_color || person.adult_specifics?.eye_color) && (
<div className="px-4 py-3 hover:bg-muted/30 transition-colors"> <div className="px-4 py-3 hover:bg-muted/30 transition-colors">
<div className="flex items-center gap-2 mb-1"> <div className="flex items-center gap-2 mb-1">
<Eye size={12} className="text-[#6d28d9]" /> <Eye size={12} className="text-[#e8466c]" />
<span className="text-[10px] text-muted-foreground uppercase tracking-wide">Eyes</span> <span className="text-[10px] text-muted-foreground uppercase tracking-wide">Eyes</span>
</div> </div>
<p className="text-sm font-medium truncate"> <p className="text-sm font-medium truncate">
@@ -360,7 +360,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
transition={{ delay: index * 0.03 }} transition={{ delay: index * 0.03 }}
> >
<Card <Card
className="hover:border-[#6d28d9]/30 hover:shadow-md transition-all duration-200 cursor-pointer group border-border/60" className="hover:border-[#e8466c]/30 hover:shadow-md transition-all duration-200 cursor-pointer group border-border/60"
onClick={() => handleMediaClick(item.id.toString())} onClick={() => handleMediaClick(item.id.toString())}
> >
<CardContent className="p-3 flex items-center gap-3"> <CardContent className="p-3 flex items-center gap-3">
@@ -374,10 +374,10 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="text-[10px] text-muted-foreground uppercase tracking-wide">Character</p> <p className="text-[10px] text-muted-foreground uppercase tracking-wide">Character</p>
<h4 className="font-semibold text-foreground truncate text-sm group-hover:text-[#6d28d9] transition-colors"> <h4 className="font-semibold text-foreground truncate text-sm group-hover:text-[#e8466c] transition-colors">
{item.characterName || item.role} {item.characterName || item.role}
</h4> </h4>
<p className="text-xs text-[#6d28d9] truncate">{item.title}</p> <p className="text-xs text-[#e8466c] truncate">{item.title}</p>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -429,7 +429,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
{option.label} {option.label}
</span> </span>
{sortBy === option.value && ( {sortBy === option.value && (
sortOrder === 'asc' ? <ArrowUpAZ size={14} className="text-[#6d28d9]" /> : <ArrowDownAZ size={14} className="text-[#6d28d9]" /> sortOrder === 'asc' ? <ArrowUpAZ size={14} className="text-[#e8466c]" /> : <ArrowDownAZ size={14} className="text-[#e8466c]" />
)} )}
</DropdownMenuItem> </DropdownMenuItem>
))} ))}
@@ -450,7 +450,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
> >
<Card <Card
onClick={() => handleMediaClick(item.id.toString())} onClick={() => handleMediaClick(item.id.toString())}
className="group cursor-pointer hover:border-[#6d28d9]/30 hover:shadow-md transition-all duration-200 border-border/60" className="group cursor-pointer hover:border-[#e8466c]/30 hover:shadow-md transition-all duration-200 border-border/60"
> >
<CardContent className="p-3 flex items-center gap-3"> <CardContent className="p-3 flex items-center gap-3">
<div className="w-12 h-16 rounded-none overflow-hidden shrink-0 bg-muted border border-border/40"> <div className="w-12 h-16 rounded-none overflow-hidden shrink-0 bg-muted border border-border/40">
@@ -462,7 +462,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP
/> />
</div> </div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<h4 className="font-semibold text-foreground truncate text-sm group-hover:text-[#6d28d9] transition-colors"> <h4 className="font-semibold text-foreground truncate text-sm group-hover:text-[#e8466c] transition-colors">
{item.title} {item.title}
</h4> </h4>
<p className="text-xs text-muted-foreground mb-1"> <p className="text-xs text-muted-foreground mb-1">
+17 -17
View File
@@ -305,7 +305,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
placeholder="Search cast..." placeholder="Search cast..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 h-9 bg-muted/50 border-none rounded-lg text-sm focus-visible:ring-[#6d28d9]/30" className="pl-9 h-9 bg-muted/50 border-none rounded-lg text-sm focus-visible:ring-[#e8466c]/30"
/> />
</div> </div>
@@ -346,7 +346,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
className={cn( className={cn(
"h-8 px-3 rounded-lg border text-xs font-medium transition-colors", "h-8 px-3 rounded-lg border text-xs font-medium transition-colors",
(sortBy !== 'roleCount' || sortOrder !== 'desc') (sortBy !== 'roleCount' || sortOrder !== 'desc')
? "border-[#6d28d9]/30 bg-[#6d28d9]/10 text-[#6d28d9] hover:bg-[#6d28d9]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50" : "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50"
)} )}
> >
@@ -378,7 +378,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
{option.label} {option.label}
</span> </span>
{sortBy === option.value && ( {sortBy === option.value && (
sortOrder === 'asc' ? <ArrowUpAZ size={14} className="text-[#6d28d9]" /> : <ArrowDownAZ size={14} className="text-[#6d28d9]" /> sortOrder === 'asc' ? <ArrowUpAZ size={14} className="text-[#e8466c]" /> : <ArrowDownAZ size={14} className="text-[#e8466c]" />
)} )}
</DropdownMenuItem> </DropdownMenuItem>
))} ))}
@@ -395,7 +395,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
className={cn( className={cn(
"h-8 px-3 rounded-lg border text-xs font-medium transition-colors", "h-8 px-3 rounded-lg border text-xs font-medium transition-colors",
filterOccupation && filterOccupation !== 'all' filterOccupation && filterOccupation !== 'all'
? "border-[#6d28d9]/30 bg-[#6d28d9]/10 text-[#6d28d9] hover:bg-[#6d28d9]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50" : "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50"
)} )}
> >
@@ -430,7 +430,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
className={cn( className={cn(
"h-8 px-3 rounded-lg border text-xs font-medium transition-colors", "h-8 px-3 rounded-lg border text-xs font-medium transition-colors",
filterMediaType && filterMediaType !== 'all' filterMediaType && filterMediaType !== 'all'
? "border-[#6d28d9]/30 bg-[#6d28d9]/10 text-[#6d28d9] hover:bg-[#6d28d9]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50" : "border-border/60 bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50"
)} )}
> >
@@ -475,7 +475,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
{searchQuery && ( {searchQuery && (
<Badge <Badge
variant="secondary" variant="secondary"
className="h-6 px-2 text-xs bg-[#6d28d9]/10 text-[#6d28d9] border-[#6d28d9]/20 hover:bg-[#6d28d9]/20 cursor-pointer" className="h-6 px-2 text-xs bg-[#e8466c]/10 text-[#e8466c] border-[#e8466c]/20 hover:bg-[#e8466c]/20 cursor-pointer"
onClick={() => setSearchQuery('')} onClick={() => setSearchQuery('')}
> >
Search: {searchQuery} Search: {searchQuery}
@@ -485,7 +485,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
{filterOccupation && filterOccupation !== 'all' && ( {filterOccupation && filterOccupation !== 'all' && (
<Badge <Badge
variant="secondary" variant="secondary"
className="h-6 px-2 text-xs bg-[#6d28d9]/10 text-[#6d28d9] border-[#6d28d9]/20 hover:bg-[#6d28d9]/20 cursor-pointer" className="h-6 px-2 text-xs bg-[#e8466c]/10 text-[#e8466c] border-[#e8466c]/20 hover:bg-[#e8466c]/20 cursor-pointer"
onClick={() => setFilterOccupation('all')} onClick={() => setFilterOccupation('all')}
> >
{filterOccupation} {filterOccupation}
@@ -495,7 +495,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
{filterMediaType && filterMediaType !== 'all' && ( {filterMediaType && filterMediaType !== 'all' && (
<Badge <Badge
variant="secondary" variant="secondary"
className="h-6 px-2 text-xs bg-[#6d28d9]/10 text-[#6d28d9] border-[#6d28d9]/20 hover:bg-[#6d28d9]/20 cursor-pointer" className="h-6 px-2 text-xs bg-[#e8466c]/10 text-[#e8466c] border-[#e8466c]/20 hover:bg-[#e8466c]/20 cursor-pointer"
onClick={() => setFilterMediaType('all')} onClick={() => setFilterMediaType('all')}
> >
{filterMediaType} {filterMediaType}
@@ -545,20 +545,20 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
transition={{ duration: 0.2 }} transition={{ duration: 0.2 }}
> >
<Card <Card
className="group cursor-pointer overflow-hidden hover:shadow-xl hover:border-[#6d28d9]/30 transition-all duration-300 border-border/60" className="group cursor-pointer overflow-hidden hover:shadow-xl hover:border-[#e8466c]/30 transition-all duration-300 border-border/60"
onClick={() => onPersonClick(person)} onClick={() => onPersonClick(person)}
> >
{/* Card Header with Avatar and Info */} {/* Card Header with Avatar and Info */}
<div className="p-3"> <div className="p-3">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<Avatar className="h-12 w-12 rounded-lg border-2 border-border/50 group-hover:border-[#6d28d9] transition-colors duration-300 shadow-sm"> <Avatar className="h-12 w-12 rounded-lg border-2 border-border/50 group-hover:border-[#e8466c] transition-colors duration-300 shadow-sm">
<AvatarImage src={person.photo} alt={person.name} referrerPolicy="no-referrer" className="object-cover" /> <AvatarImage src={person.photo} alt={person.name} referrerPolicy="no-referrer" className="object-cover" />
<AvatarFallback className="rounded-lg bg-muted"> <AvatarFallback className="rounded-lg bg-muted">
<User className="h-5 w-5 text-muted-foreground" /> <User className="h-5 w-5 text-muted-foreground" />
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<h3 className="font-semibold text-foreground truncate group-hover:text-[#6d28d9] transition-colors duration-300 text-sm leading-tight"> <h3 className="font-semibold text-foreground truncate group-hover:text-[#e8466c] transition-colors duration-300 text-sm leading-tight">
{person.name} {person.name}
</h3> </h3>
<p className="text-[11px] text-muted-foreground mt-0.5 truncate"> <p className="text-[11px] text-muted-foreground mt-0.5 truncate">
@@ -592,7 +592,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
{/* Latest Role Section */} {/* Latest Role Section */}
{person.filmography && person.filmography.length > 0 && ( {person.filmography && person.filmography.length > 0 && (
<div className="px-3 pb-3"> <div className="px-3 pb-3">
<div className="bg-muted/50 rounded-lg p-2 flex items-center gap-2 border border-border/40 group-hover:border-[#6d28d9]/20 transition-colors"> <div className="bg-muted/50 rounded-lg p-2 flex items-center gap-2 border border-border/40 group-hover:border-[#e8466c]/20 transition-colors">
<div className="w-8 h-11 rounded overflow-hidden shrink-0 bg-background border border-border/40"> <div className="w-8 h-11 rounded overflow-hidden shrink-0 bg-background border border-border/40">
<img <img
src={person.filmography[0].poster || person.photo} src={person.filmography[0].poster || person.photo}
@@ -604,7 +604,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="text-[10px] text-muted-foreground uppercase tracking-wide leading-none">Latest</p> <p className="text-[10px] text-muted-foreground uppercase tracking-wide leading-none">Latest</p>
<p className="text-[11px] font-medium text-foreground truncate">{person.filmography[0].title}</p> <p className="text-[11px] font-medium text-foreground truncate">{person.filmography[0].title}</p>
<p className="text-[10px] text-[#6d28d9] truncate">{person.filmography[0].role}</p> <p className="text-[10px] text-[#e8466c] truncate">{person.filmography[0].role}</p>
</div> </div>
</div> </div>
</div> </div>
@@ -621,7 +621,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
<TableRow className="hover:bg-transparent border-border/60 bg-muted/30"> <TableRow className="hover:bg-transparent border-border/60 bg-muted/30">
<TableHead className="w-14 rounded-tl-lg"></TableHead> <TableHead className="w-14 rounded-tl-lg"></TableHead>
<TableHead <TableHead
className="cursor-pointer hover:text-[#6d28d9] transition-colors" className="cursor-pointer hover:text-[#e8466c] transition-colors"
onClick={() => handleSort('name')} onClick={() => handleSort('name')}
> >
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
@@ -630,7 +630,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="cursor-pointer hover:text-[#6d28d9] transition-colors" className="cursor-pointer hover:text-[#e8466c] transition-colors"
onClick={() => handleSort('role')} onClick={() => handleSort('role')}
> >
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
@@ -640,7 +640,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
</TableHead> </TableHead>
<TableHead className="hidden md:table-cell">Latest Work</TableHead> <TableHead className="hidden md:table-cell">Latest Work</TableHead>
<TableHead <TableHead
className="hidden sm:table-cell cursor-pointer hover:text-[#6d28d9] transition-colors text-right" className="hidden sm:table-cell cursor-pointer hover:text-[#e8466c] transition-colors text-right"
onClick={() => handleSort('roleCount')} onClick={() => handleSort('roleCount')}
> >
<div className="flex items-center justify-end gap-1"> <div className="flex items-center justify-end gap-1">
@@ -678,7 +678,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag
</TableCell> </TableCell>
<TableCell className="font-medium"> <TableCell className="font-medium">
<div className="flex flex-col"> <div className="flex flex-col">
<span className="group-hover:text-[#6d28d9] transition-colors">{person.name}</span> <span className="group-hover:text-[#e8466c] transition-colors">{person.name}</span>
{person.birthDate && ( {person.birthDate && (
<span className="text-xs text-muted-foreground"> <span className="text-xs text-muted-foreground">
{new Date(person.birthDate).toLocaleDateString()} {new Date(person.birthDate).toLocaleDateString()}
+12 -12
View File
@@ -133,11 +133,11 @@ export default function DashboardView({ mediaList, onMediaClick, loading = false
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#e8466c] to-[#f47298] flex items-center justify-center"> <div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#e8466c] to-[#f47298] flex items-center justify-center">
<Sparkles className="w-4 h-4 text-white" /> <Sparkles className="w-4 h-4 text-white" />
</div> </div>
<h1 className="text-2xl font-bold text-white"> <h1 className="text-2xl font-bold text-foreground">
Welcome to MediaVault Welcome to MediaVault
</h1> </h1>
</div> </div>
<p className="text-gray-400 text-sm ml-11">Your media library at a glance</p> <p className="text-muted-foreground text-sm ml-11">Your media library at a glance</p>
</motion.div> </motion.div>
{/* Stats Cards */} {/* Stats Cards */}
@@ -156,12 +156,12 @@ export default function DashboardView({ mediaList, onMediaClick, loading = false
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 + index * 0.05 }} transition={{ delay: 0.1 + index * 0.05 }}
onClick={() => navigate(card.path)} onClick={() => navigate(card.path)}
className={`relative overflow-hidden rounded-xl p-5 bg-gradient-to-br ${card.color} border border-white/5 hover:border-white/10 transition-all duration-300 cursor-pointer group`} className={`relative overflow-hidden rounded-xl p-5 bg-gradient-to-br ${card.color} border border-border/50 hover:border-border/80 transition-all duration-300 cursor-pointer group`}
> >
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div> <div>
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-1">{card.label}</p> <p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-1">{card.label}</p>
<p className="text-3xl font-bold text-white">{card.count}</p> <p className="text-3xl font-bold text-foreground">{card.count}</p>
</div> </div>
<div className={`w-10 h-10 rounded-lg ${card.iconBg} flex items-center justify-center`}> <div className={`w-10 h-10 rounded-lg ${card.iconBg} flex items-center justify-center`}>
<Icon className="w-5 h-5 text-white" /> <Icon className="w-5 h-5 text-white" />
@@ -191,10 +191,10 @@ export default function DashboardView({ mediaList, onMediaClick, loading = false
</div> </div>
<div> <div>
<p className="text-xs font-semibold text-[#e8466c] uppercase tracking-wider">FAVORITES</p> <p className="text-xs font-semibold text-[#e8466c] uppercase tracking-wider">FAVORITES</p>
<p className="text-2xl font-bold text-white">{favoritesMedia.length} <span className="text-sm font-normal text-gray-400">items in your favorites</span></p> <p className="text-2xl font-bold text-foreground">{favoritesMedia.length} <span className="text-sm font-normal text-muted-foreground">items in your favorites</span></p>
</div> </div>
</div> </div>
<div className="flex items-center gap-2 text-gray-400 group-hover:text-white transition-colors"> <div className="flex items-center gap-2 text-muted-foreground group-hover:text-foreground transition-colors">
<span className="text-sm font-medium">View Favorites</span> <span className="text-sm font-medium">View Favorites</span>
<ChevronRight className="w-5 h-5" /> <ChevronRight className="w-5 h-5" />
</div> </div>
@@ -214,11 +214,11 @@ export default function DashboardView({ mediaList, onMediaClick, loading = false
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Clock className="w-5 h-5 text-[#e8466c]" /> <Clock className="w-5 h-5 text-[#e8466c]" />
<h2 className="text-sm font-bold text-white uppercase tracking-wider">Recently Added</h2> <h2 className="text-sm font-bold text-foreground uppercase tracking-wider">Recently Added</h2>
</div> </div>
<button <button
onClick={() => navigate('/browse?sort=recent')} onClick={() => navigate('/browse?sort=recent')}
className="flex items-center gap-1 text-sm text-gray-400 hover:text-white transition-colors" className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors"
> >
View All <ChevronRight className="w-4 h-4" /> View All <ChevronRight className="w-4 h-4" />
</button> </button>
@@ -240,11 +240,11 @@ export default function DashboardView({ mediaList, onMediaClick, loading = false
{/* Empty State */} {/* Empty State */}
{mediaList.length === 0 && ( {mediaList.length === 0 && (
<div className="flex flex-col items-center justify-center py-32 text-gray-400"> <div className="flex flex-col items-center justify-center py-32 text-muted-foreground">
<div className="w-20 h-20 bg-white/5 rounded-2xl flex items-center justify-center mb-6 border border-white/10"> <div className="w-20 h-20 bg-muted rounded-2xl flex items-center justify-center mb-6 border border-border">
<Database className="w-10 h-10" /> <Database className="w-10 h-10" />
</div> </div>
<p className="text-xl font-bold text-white">No media found</p> <p className="text-xl font-bold text-foreground">No media found</p>
<p className="text-sm">Start by adding media to your collection</p> <p className="text-sm">Start by adding media to your collection</p>
</div> </div>
)} )}
+7 -7
View File
@@ -72,7 +72,7 @@ export default function Header({
? "bg-transparent" ? "bg-transparent"
: transparent && scrolled : transparent && scrolled
? "backdrop-blur-xl bg-background/70 border-b border-border/30" ? "backdrop-blur-xl bg-background/70 border-b border-border/30"
: "backdrop-blur-xl bg-gradient-to-r from-[#6d28d9]/90 via-[#8b5cf6]/90 to-[#6d28d9]/90 border-b border-white/10" : "backdrop-blur-xl bg-gradient-to-r from-[#e8466c]/90 via-[#f47298]/90 to-[#e8466c]/90 border-b border-white/10"
)} )}
> >
<div className="flex items-center gap-8"> <div className="flex items-center gap-8">
@@ -87,7 +87,7 @@ export default function Header({
"w-8 h-8 rounded-xl flex items-center justify-center shadow-lg transition-all duration-300", "w-8 h-8 rounded-xl flex items-center justify-center shadow-lg transition-all duration-300",
(transparent && !scrolled) || !transparent (transparent && !scrolled) || !transparent
? "bg-white/20 backdrop-blur-sm border border-white/30" ? "bg-white/20 backdrop-blur-sm border border-white/30"
: "bg-gradient-to-br from-[#6d28d9] to-[#8b5cf6] shadow-[#6d28d9]/30" : "bg-gradient-to-br from-[#e8466c] to-[#f47298] shadow-[#e8466c]/30"
)}> )}>
<div className={cn( <div className={cn(
"w-4 h-4 rounded-full", "w-4 h-4 rounded-full",
@@ -121,7 +121,7 @@ export default function Header({
? "text-white bg-white/10" ? "text-white bg-white/10"
: "text-white/70 hover:text-white hover:bg-white/5" : "text-white/70 hover:text-white hover:bg-white/5"
: isActive : isActive
? "text-foreground bg-[#6d28d9]/10" ? "text-foreground bg-[#e8466c]/10"
: "text-muted-foreground hover:text-foreground hover:bg-muted" : "text-muted-foreground hover:text-foreground hover:bg-muted"
)} )}
> >
@@ -138,7 +138,7 @@ export default function Header({
"text-sm font-bold transition-all duration-300 uppercase tracking-wider px-4 py-2 rounded-lg", "text-sm font-bold transition-all duration-300 uppercase tracking-wider px-4 py-2 rounded-lg",
(transparent && !scrolled) || !transparent (transparent && !scrolled) || !transparent
? isActive ? "text-white bg-white/10" : "text-white/70 hover:text-white hover:bg-white/5" ? isActive ? "text-white bg-white/10" : "text-white/70 hover:text-white hover:bg-white/5"
: isActive ? "text-foreground bg-[#6d28d9]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted" : isActive ? "text-foreground bg-[#e8466c]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted"
)} )}
> >
CAST CAST
@@ -215,7 +215,7 @@ export default function Header({
"w-9 h-9 rounded-xl overflow-hidden border-2 transition-all duration-300 hover:scale-110 hover:shadow-lg", "w-9 h-9 rounded-xl overflow-hidden border-2 transition-all duration-300 hover:scale-110 hover:shadow-lg",
(transparent && !scrolled) || !transparent (transparent && !scrolled) || !transparent
? "border-white/30 hover:border-white/50" ? "border-white/30 hover:border-white/50"
: "border-border hover:border-[#6d28d9]/50" : "border-border hover:border-[#e8466c]/50"
)}> )}>
<img <img
src="https://picsum.photos/seed/user/100/100" src="https://picsum.photos/seed/user/100/100"
@@ -237,7 +237,7 @@ export default function Header({
onClick={() => setIsMobileMenuOpen(false)} onClick={() => setIsMobileMenuOpen(false)}
className={({ isActive }) => cn( className={({ isActive }) => cn(
"text-sm font-bold transition-colors uppercase tracking-wider py-2 px-4 rounded-lg", "text-sm font-bold transition-colors uppercase tracking-wider py-2 px-4 rounded-lg",
isActive ? "text-[#6d28d9] bg-[#6d28d9]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted" isActive ? "text-[#e8466c] bg-[#e8466c]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted"
)} )}
> >
{cat} {cat}
@@ -249,7 +249,7 @@ export default function Header({
onClick={() => setIsMobileMenuOpen(false)} onClick={() => setIsMobileMenuOpen(false)}
className={({ isActive }) => cn( className={({ isActive }) => cn(
"text-sm font-bold transition-colors uppercase tracking-wider py-2 px-4 rounded-lg", "text-sm font-bold transition-colors uppercase tracking-wider py-2 px-4 rounded-lg",
isActive ? "text-[#6d28d9] bg-[#6d28d9]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted" isActive ? "text-[#e8466c] bg-[#e8466c]/10" : "text-muted-foreground hover:text-foreground hover:bg-muted"
)} )}
> >
CAST CAST
+2 -2
View File
@@ -418,7 +418,7 @@ export default function ImporterView() {
<Button <Button
onClick={handleXBVRImport} onClick={handleXBVRImport}
disabled={progress.stage !== 'idle' || !xbvrConfig.url} disabled={progress.stage !== 'idle' || !xbvrConfig.url}
className="w-full bg-[#6d28d9] hover:bg-[#5b21b6] text-white font-bold" className="w-full bg-[#6d28d9] hover:bg-[#d13d60] text-white font-bold"
> >
{progress.stage === 'fetching' || progress.stage === 'importing' ? ( {progress.stage === 'fetching' || progress.stage === 'importing' ? (
<> <>
@@ -1010,7 +1010,7 @@ export default function ImporterView() {
<div <div
className={cn( className={cn(
"h-full transition-all duration-300 ease-out", "h-full transition-all duration-300 ease-out",
progress.stage === 'error' ? "bg-gradient-to-r from-red-500 to-red-600" : "bg-gradient-to-r from-[#6d28d9] to-[#8b5cf6]" progress.stage === 'error' ? "bg-gradient-to-r from-red-500 to-red-600" : "bg-gradient-to-r from-[#6d28d9] to-[#f47298]"
)} )}
style={{ width: `${getProgressPercentage()}%` }} style={{ width: `${getProgressPercentage()}%` }}
/> />
+2 -2
View File
@@ -48,9 +48,9 @@ export default function LibrarySettings({ enabledCategories, onToggleCategory }:
</DialogHeader> </DialogHeader>
<div className="grid gap-6 py-6"> <div className="grid gap-6 py-6">
{categories.map((category) => ( {categories.map((category) => (
<div key={category} className="flex items-center justify-between p-4 rounded-2xl bg-muted/30 border border-border/50 transition-all hover:border-[#6d28d9]/30 hover:bg-muted/50"> <div key={category} className="flex items-center justify-between p-4 rounded-2xl bg-muted/30 border border-border/50 transition-all hover:border-[#e8466c]/30 hover:bg-muted/50">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="w-10 h-10 rounded-xl bg-background flex items-center justify-center text-[#6d28d9] shadow-sm border border-border/30"> <div className="w-10 h-10 rounded-xl bg-background flex items-center justify-center text-[#e8466c] shadow-sm border border-border/30">
{CATEGORY_ICONS[category]} {CATEGORY_ICONS[category]}
</div> </div>
<div> <div>
+15 -15
View File
@@ -13,14 +13,14 @@ interface MediaListItemProps {
} }
const categoryConfig: Record<MediaCategory, { label: string; color: string; bgColor: string; icon: any }> = { const categoryConfig: Record<MediaCategory, { label: string; color: string; bgColor: string; icon: any }> = {
'Anime': { label: 'ANIME', color: 'text-purple-300', bgColor: 'bg-purple-500/30', icon: null }, 'Anime': { label: 'ANIME', color: 'text-purple-400', bgColor: 'bg-purple-500/20', icon: null },
'Movies': { label: 'MOVIE', color: 'text-blue-300', bgColor: 'bg-blue-500/30', icon: Film }, 'Movies': { label: 'MOVIE', color: 'text-blue-400', bgColor: 'bg-blue-500/20', icon: Film },
'TV Series': { label: 'SERIES', color: 'text-green-300', bgColor: 'bg-green-500/30', icon: Tv }, 'TV Series': { label: 'SERIES', color: 'text-green-400', bgColor: 'bg-green-500/20', icon: Tv },
'Music': { label: 'MUSIC', color: 'text-pink-300', bgColor: 'bg-pink-500/30', icon: null }, 'Music': { label: 'MUSIC', color: 'text-pink-400', bgColor: 'bg-pink-500/20', icon: null },
'Books': { label: 'BOOK', color: 'text-yellow-300', bgColor: 'bg-yellow-500/30', icon: null }, 'Books': { label: 'BOOK', color: 'text-yellow-400', bgColor: 'bg-yellow-500/20', icon: null },
'Games': { label: 'GAME', color: 'text-indigo-300', bgColor: 'bg-indigo-500/30', icon: Gamepad2 }, 'Games': { label: 'GAME', color: 'text-indigo-400', bgColor: 'bg-indigo-500/20', icon: Gamepad2 },
'Consoles': { label: 'CONSOLE', color: 'text-orange-300', bgColor: 'bg-orange-500/30', icon: null }, 'Consoles': { label: 'CONSOLE', color: 'text-orange-400', bgColor: 'bg-orange-500/20', icon: null },
'Adult': { label: 'ADULT', color: 'text-rose-300', bgColor: 'bg-rose-500/30', icon: Eye }, 'Adult': { label: 'ADULT', color: 'text-rose-400', bgColor: 'bg-rose-500/20', icon: Eye },
}; };
export default function MediaListItem({ media, onClick, isFavorite = false, onFavoriteToggle }: MediaListItemProps) { export default function MediaListItem({ media, onClick, isFavorite = false, onFavoriteToggle }: MediaListItemProps) {
@@ -38,13 +38,13 @@ export default function MediaListItem({ media, onClick, isFavorite = false, onFa
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
exit={{ opacity: 0 }} exit={{ opacity: 0 }}
className="group flex items-center px-4 py-2 hover:bg-white/[0.02] transition-colors cursor-pointer border-b border-white/[0.02] last:border-b-0" className="group flex items-center px-4 py-2 hover:bg-muted/30 transition-colors cursor-pointer border-b border-border/30 last:border-b-0"
onClick={() => onClick(media)} onClick={() => onClick(media)}
> >
{/* TITLE Column: Poster + Title + Rating (like screenshot 2) */} {/* TITLE Column: Poster + Title + Rating (like screenshot 2) */}
<div className="flex-1 min-w-0 flex items-center gap-3 mr-4"> <div className="flex-1 min-w-0 flex items-center gap-3 mr-4">
{/* Poster Thumbnail */} {/* Poster Thumbnail */}
<div className="relative w-10 h-14 rounded overflow-hidden shrink-0 bg-[#1a1d26]"> <div className="relative w-10 h-14 rounded overflow-hidden shrink-0 bg-muted">
<img <img
src={media.poster} src={media.poster}
alt={media.title} alt={media.title}
@@ -55,7 +55,7 @@ export default function MediaListItem({ media, onClick, isFavorite = false, onFa
{/* Title + Rating stacked */} {/* Title + Rating stacked */}
<div className="min-w-0"> <div className="min-w-0">
<h3 className="text-sm font-medium text-gray-200 truncate group-hover:text-[#e8466c] transition-colors"> <h3 className="text-sm font-medium text-foreground truncate group-hover:text-[#e8466c] transition-colors">
{media.title} {media.title}
</h3> </h3>
<div className="flex items-center gap-1 mt-0.5"> <div className="flex items-center gap-1 mt-0.5">
@@ -81,19 +81,19 @@ export default function MediaListItem({ media, onClick, isFavorite = false, onFa
{/* GENRE Column */} {/* GENRE Column */}
<div className="w-[140px] shrink-0 mr-4"> <div className="w-[140px] shrink-0 mr-4">
<span className="text-sm text-gray-500 truncate block"> <span className="text-sm text-muted-foreground truncate block">
{media.genres?.slice(0, 2).join(', ') || '-'} {media.genres?.slice(0, 2).join(', ') || '-'}
</span> </span>
</div> </div>
{/* YEAR Column */} {/* YEAR Column */}
<div className="w-[60px] shrink-0 text-center mr-4"> <div className="w-[60px] shrink-0 text-center mr-4">
<span className="text-sm text-gray-400">{media.year}</span> <span className="text-sm text-muted-foreground/80">{media.year}</span>
</div> </div>
{/* PLAYS Column */} {/* PLAYS Column */}
<div className="w-[50px] shrink-0 text-right mr-4"> <div className="w-[50px] shrink-0 text-right mr-4">
<span className="text-sm text-gray-400">{media.playCount || 0}</span> <span className="text-sm text-muted-foreground/80">{media.playCount || 0}</span>
</div> </div>
{/* FAVORITE Column (Heart) */} {/* FAVORITE Column (Heart) */}
@@ -104,7 +104,7 @@ export default function MediaListItem({ media, onClick, isFavorite = false, onFa
"p-1 rounded transition-colors", "p-1 rounded transition-colors",
isFavorite isFavorite
? "text-[#e8466c]" ? "text-[#e8466c]"
: "text-gray-600 hover:text-gray-500" : "text-muted-foreground/40 hover:text-muted-foreground/60"
)} )}
> >
<Heart size={14} className={cn(isFavorite && "fill-current")} /> <Heart size={14} className={cn(isFavorite && "fill-current")} />
+24 -24
View File
@@ -41,14 +41,14 @@ const categoryConfig: Record<MediaCategory, {
bgColor: string; bgColor: string;
icon: React.ElementType | null; icon: React.ElementType | null;
}> = { }> = {
'Anime': { label: 'ANIME', color: 'text-purple-300', bgColor: 'bg-purple-500/30', icon: null }, 'Anime': { label: 'ANIME', color: 'text-purple-400', bgColor: 'bg-purple-500/20', icon: null },
'Movies': { label: 'MOVIE', color: 'text-blue-300', bgColor: 'bg-blue-500/30', icon: Film }, 'Movies': { label: 'MOVIE', color: 'text-blue-400', bgColor: 'bg-blue-500/20', icon: Film },
'TV Series': { label: 'SERIES', color: 'text-green-300', bgColor: 'bg-green-500/30', icon: Tv }, 'TV Series': { label: 'SERIES', color: 'text-green-400', bgColor: 'bg-green-500/20', icon: Tv },
'Music': { label: 'MUSIC', color: 'text-pink-300', bgColor: 'bg-pink-500/30', icon: Music }, 'Music': { label: 'MUSIC', color: 'text-pink-400', bgColor: 'bg-pink-500/20', icon: Music },
'Books': { label: 'BOOK', color: 'text-yellow-300', bgColor: 'bg-yellow-500/30', icon: BookOpen }, 'Books': { label: 'BOOK', color: 'text-yellow-400', bgColor: 'bg-yellow-500/20', icon: BookOpen },
'Games': { label: 'GAME', color: 'text-indigo-300', bgColor: 'bg-indigo-500/30', icon: Gamepad2 }, 'Games': { label: 'GAME', color: 'text-indigo-400', bgColor: 'bg-indigo-500/20', icon: Gamepad2 },
'Consoles': { label: 'CONSOLE', color: 'text-orange-300', bgColor: 'bg-orange-500/30', icon: Monitor }, 'Consoles': { label: 'CONSOLE', color: 'text-orange-400', bgColor: 'bg-orange-500/20', icon: Monitor },
'Adult': { label: 'ADULT', color: 'text-rose-300', bgColor: 'bg-rose-500/30', icon: Eye }, 'Adult': { label: 'ADULT', color: 'text-rose-400', bgColor: 'bg-rose-500/20', icon: Eye },
}; };
export default function MediaTable({ export default function MediaTable({
@@ -104,7 +104,7 @@ export default function MediaTable({
const SortIcon = ({ field }: { field: SortField }) => { const SortIcon = ({ field }: { field: SortField }) => {
if (sortField !== field) { if (sortField !== field) {
return <ArrowUpDown size={14} className="text-gray-600 ml-1 opacity-0 group-hover:opacity-100 transition-opacity" />; return <ArrowUpDown size={14} className="text-muted-foreground/40 ml-1 opacity-0 group-hover:opacity-100 transition-opacity" />;
} }
return sortDirection === 'asc' return sortDirection === 'asc'
? <ArrowUp size={14} className="text-[#e8466c] ml-1" /> ? <ArrowUp size={14} className="text-[#e8466c] ml-1" />
@@ -119,9 +119,9 @@ export default function MediaTable({
return ( return (
<Table className="w-full"> <Table className="w-full">
<TableHeader> <TableHeader>
<TableRow className="border-b border-white/[0.03] hover:bg-transparent"> <TableRow className="border-b border-border/20 hover:bg-transparent">
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[45%]" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[45%]"
onClick={() => handleSort('title')} onClick={() => handleSort('title')}
> >
<div className="flex items-center"> <div className="flex items-center">
@@ -129,7 +129,7 @@ export default function MediaTable({
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[80px]" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[80px]"
onClick={() => handleSort('category')} onClick={() => handleSort('category')}
> >
<div className="flex items-center"> <div className="flex items-center">
@@ -137,7 +137,7 @@ export default function MediaTable({
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[18%]" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[18%]"
onClick={() => handleSort('genre')} onClick={() => handleSort('genre')}
> >
<div className="flex items-center"> <div className="flex items-center">
@@ -145,7 +145,7 @@ export default function MediaTable({
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[70px] text-center" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[70px] text-center"
onClick={() => handleSort('rating')} onClick={() => handleSort('rating')}
> >
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
@@ -153,7 +153,7 @@ export default function MediaTable({
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[60px] text-center" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[60px] text-center"
onClick={() => handleSort('year')} onClick={() => handleSort('year')}
> >
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
@@ -161,7 +161,7 @@ export default function MediaTable({
</div> </div>
</TableHead> </TableHead>
<TableHead <TableHead
className="text-xs font-semibold text-gray-500 uppercase tracking-wider cursor-pointer hover:text-gray-300 transition-colors group w-[60px] text-right" className="text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/80 transition-colors group w-[60px] text-right"
onClick={() => handleSort('plays')} onClick={() => handleSort('plays')}
> >
<div className="flex items-center justify-end"> <div className="flex items-center justify-end">
@@ -180,13 +180,13 @@ export default function MediaTable({
return ( return (
<TableRow <TableRow
key={media.id} key={media.id}
className="border-b border-white/[0.02] hover:bg-white/[0.02] transition-colors cursor-pointer group" className="border-b border-border/20 hover:bg-muted/30 transition-colors cursor-pointer group"
onClick={() => onMediaClick(media)} onClick={() => onMediaClick(media)}
> >
{/* Title Cell with Poster */} {/* Title Cell with Poster */}
<TableCell className="py-2"> <TableCell className="py-2">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="relative w-10 h-14 rounded overflow-hidden shrink-0 bg-[#1a1d26]"> <div className="relative w-10 h-14 rounded overflow-hidden shrink-0 bg-muted">
<img <img
src={media.poster} src={media.poster}
alt={media.title} alt={media.title}
@@ -195,7 +195,7 @@ export default function MediaTable({
/> />
</div> </div>
<div className="min-w-0"> <div className="min-w-0">
<div className="text-sm font-medium text-gray-200 truncate group-hover:text-[#e8466c] transition-colors"> <div className="text-sm font-medium text-foreground truncate group-hover:text-[#e8466c] transition-colors">
{media.title} {media.title}
</div> </div>
</div> </div>
@@ -216,7 +216,7 @@ export default function MediaTable({
{/* Genre */} {/* Genre */}
<TableCell> <TableCell>
<span className="text-sm text-gray-500 truncate block"> <span className="text-sm text-muted-foreground truncate block">
{media.genres?.join(', ') || '-'} {media.genres?.join(', ') || '-'}
</span> </span>
</TableCell> </TableCell>
@@ -225,7 +225,7 @@ export default function MediaTable({
<TableCell className="text-center"> <TableCell className="text-center">
<div className="flex items-center justify-center gap-1"> <div className="flex items-center justify-center gap-1">
<Star size={12} className="text-[#e8466c] fill-[#e8466c]" /> <Star size={12} className="text-[#e8466c] fill-[#e8466c]" />
<span className="text-sm font-medium text-gray-300"> <span className="text-sm font-medium text-foreground/80">
{media.rating?.toFixed(1) || '-'} {media.rating?.toFixed(1) || '-'}
</span> </span>
</div> </div>
@@ -233,12 +233,12 @@ export default function MediaTable({
{/* Year */} {/* Year */}
<TableCell className="text-center"> <TableCell className="text-center">
<span className="text-sm text-gray-400">{media.year}</span> <span className="text-sm text-muted-foreground/80">{media.year}</span>
</TableCell> </TableCell>
{/* Plays */} {/* Plays */}
<TableCell className="text-right"> <TableCell className="text-right">
<span className="text-sm text-gray-400">{media.playCount || 0}</span> <span className="text-sm text-muted-foreground/80">{media.playCount || 0}</span>
</TableCell> </TableCell>
{/* Favorite */} {/* Favorite */}
@@ -249,7 +249,7 @@ export default function MediaTable({
"p-1 rounded transition-colors", "p-1 rounded transition-colors",
isFavorite isFavorite
? "text-[#e8466c]" ? "text-[#e8466c]"
: "text-gray-600 hover:text-gray-500" : "text-muted-foreground/40 hover:text-muted-foreground/60"
)} )}
> >
<Heart size={14} className={cn(isFavorite && "fill-current")} /> <Heart size={14} className={cn(isFavorite && "fill-current")} />
+2 -2
View File
@@ -559,14 +559,14 @@ export default function SettingsView({ onSettingsSaved }: SettingsViewProps) {
<div className="flex gap-2"> <div className="flex gap-2">
<input <input
type="color" type="color"
value={customColors[key as keyof CustomColors] || '#6d28d9'} value={customColors[key as keyof CustomColors] || '#e8466c'}
onChange={(e) => handleColorChange(key as keyof CustomColors, e.target.value)} onChange={(e) => handleColorChange(key as keyof CustomColors, e.target.value)}
className="w-10 h-10 rounded-lg cursor-pointer border-0 p-0" className="w-10 h-10 rounded-lg cursor-pointer border-0 p-0"
/> />
<Input <Input
value={customColors[key as keyof CustomColors] || ''} value={customColors[key as keyof CustomColors] || ''}
onChange={(e) => handleColorChange(key as keyof CustomColors, e.target.value)} onChange={(e) => handleColorChange(key as keyof CustomColors, e.target.value)}
placeholder="#6d28d9" placeholder="#e8466c"
className="flex-1 text-xs" className="flex-1 text-xs"
/> />
</div> </div>
+13 -13
View File
@@ -123,14 +123,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedGenre selectedGenre
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<Star size={14} className="mr-2" /> <Star size={14} className="mr-2" />
{selectedGenre || 'Genres'} {selectedGenre || 'Genres'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Genre Filter by Genre
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -153,14 +153,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedStudio selectedStudio
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<Building2 size={14} className="mr-2" /> <Building2 size={14} className="mr-2" />
{selectedStudio || 'Studios'} {selectedStudio || 'Studios'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Studio Filter by Studio
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -184,14 +184,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedPlatform selectedPlatform
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<Monitor size={14} className="mr-2" /> <Monitor size={14} className="mr-2" />
{selectedPlatform || 'Platforms'} {selectedPlatform || 'Platforms'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Platform Filter by Platform
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -215,14 +215,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedDeveloper selectedDeveloper
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<Users size={14} className="mr-2" /> <Users size={14} className="mr-2" />
{selectedDeveloper || 'Developers'} {selectedDeveloper || 'Developers'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Developer Filter by Developer
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -246,14 +246,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedCategory selectedCategory
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<FolderTree size={14} className="mr-2" /> <FolderTree size={14} className="mr-2" />
{selectedCategory || 'Series'} {selectedCategory || 'Series'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Series Filter by Series
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -277,14 +277,14 @@ export default function MediaFilters({
"h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center", "h-9 px-3 rounded-xl border text-sm font-medium transition-colors inline-flex items-center justify-center",
selectedSource selectedSource
? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20" ? "border-[#e8466c]/30 bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20"
: "border-white/10 bg-transparent text-gray-400 hover:text-white hover:bg-white/5" : "border-border bg-transparent text-muted-foreground hover:text-foreground hover:bg-accent"
)} )}
> >
<Database size={14} className="mr-2" /> <Database size={14} className="mr-2" />
{selectedSource || 'Source'} {selectedSource || 'Source'}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto"> <DropdownMenuContent align="start" className="w-48 max-h-[300px] overflow-y-auto">
<DropdownMenuItem disabled className="text-xs font-semibold text-gray-500 uppercase"> <DropdownMenuItem disabled className="text-xs font-semibold text-muted-foreground uppercase">
Filter by Source Filter by Source
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
@@ -304,7 +304,7 @@ export default function MediaFilters({
{hasActiveFilters && ( {hasActiveFilters && (
<button <button
onClick={onClearAll} onClick={onClearAll}
className="h-9 px-3 inline-flex items-center justify-center text-gray-400 hover:text-white hover:bg-white/5 rounded-lg transition-colors" className="h-9 px-3 inline-flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-accent rounded-lg transition-colors"
> >
<X size={14} className="mr-2" /> <X size={14} className="mr-2" />
Clear Clear
+18 -22
View File
@@ -143,20 +143,20 @@ export default function AppSidebar({
}); });
return ( return (
<Sidebar className="border-r border-white/5 bg-[#0d0f14]"> <Sidebar>
<SidebarHeader className="p-4"> <SidebarHeader className="p-4">
<NavLink to="/" className="flex items-center gap-3"> <NavLink to="/" className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#e8466c] to-[#f47298] flex items-center justify-center shadow-lg shadow-[#e8466c]/20"> <div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#e8466c] to-[#f47298] flex items-center justify-center shadow-lg shadow-[#e8466c]/20">
<Database className="w-4 h-4 text-white" /> <Database className="w-4 h-4 text-white" />
</div> </div>
<span className="text-lg font-bold text-white tracking-tight">{pageTitle}</span> <span className="text-lg font-bold text-sidebar-foreground tracking-tight">{pageTitle}</span>
</NavLink> </NavLink>
</SidebarHeader> </SidebarHeader>
<SidebarContent className="px-2"> <SidebarContent className="px-2">
{/* Main Navigation */} {/* Main Navigation */}
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel className="text-xs font-semibold text-gray-500 uppercase tracking-wider"> <SidebarGroupLabel>
Navigation Navigation
</SidebarGroupLabel> </SidebarGroupLabel>
<SidebarGroupContent> <SidebarGroupContent>
@@ -167,10 +167,9 @@ export default function AppSidebar({
asChild asChild
isActive={item.isActive} isActive={item.isActive}
className={cn( className={cn(
'transition-colors w-full',
item.isActive item.isActive
? 'bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20' ? 'bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20'
: 'text-gray-400 hover:bg-white/5 hover:text-white' : ''
)} )}
> >
<NavLink to={item.to} className="flex items-center gap-2 w-full"> <NavLink to={item.to} className="flex items-center gap-2 w-full">
@@ -186,7 +185,7 @@ export default function AppSidebar({
{/* Media Type Filters */} {/* Media Type Filters */}
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel className="text-xs font-semibold text-gray-500 uppercase tracking-wider"> <SidebarGroupLabel>
Media Type Media Type
</SidebarGroupLabel> </SidebarGroupLabel>
<SidebarGroupContent> <SidebarGroupContent>
@@ -199,10 +198,9 @@ export default function AppSidebar({
onClick={() => handleFilterClick(filter.category)} onClick={() => handleFilterClick(filter.category)}
isActive={isFilterActive} isActive={isFilterActive}
className={cn( className={cn(
'transition-colors w-full justify-start gap-2',
isFilterActive isFilterActive
? 'bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20' ? 'bg-[#e8466c]/10 text-[#e8466c] hover:bg-[#e8466c]/20'
: 'text-gray-400 hover:bg-white/5 hover:text-white' : ''
)} )}
> >
<filter.icon <filter.icon
@@ -217,7 +215,7 @@ export default function AppSidebar({
'ml-auto text-xs font-medium px-2 py-0.5 rounded-full shrink-0', 'ml-auto text-xs font-medium px-2 py-0.5 rounded-full shrink-0',
isFilterActive isFilterActive
? 'bg-[#e8466c]/20 text-[#e8466c]' ? 'bg-[#e8466c]/20 text-[#e8466c]'
: 'bg-white/10 text-gray-500' : 'bg-sidebar-accent text-sidebar-foreground/60'
)} )}
> >
{filter.count} {filter.count}
@@ -232,7 +230,7 @@ export default function AppSidebar({
{/* Quick Filters */} {/* Quick Filters */}
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel className="text-xs font-semibold text-gray-500 uppercase tracking-wider"> <SidebarGroupLabel>
Quick Filters Quick Filters
</SidebarGroupLabel> </SidebarGroupLabel>
<SidebarGroupContent> <SidebarGroupContent>
@@ -240,7 +238,6 @@ export default function AppSidebar({
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton <SidebarMenuButton
onClick={() => handleQuickFilter('most-played')} onClick={() => handleQuickFilter('most-played')}
className="text-gray-400 hover:bg-white/5 hover:text-white w-full justify-start gap-2"
> >
<Flame className="w-4 h-4 text-orange-400 shrink-0" /> <Flame className="w-4 h-4 text-orange-400 shrink-0" />
<span className="truncate">Most Played</span> <span className="truncate">Most Played</span>
@@ -249,7 +246,6 @@ export default function AppSidebar({
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton <SidebarMenuButton
onClick={() => handleQuickFilter('recently-added')} onClick={() => handleQuickFilter('recently-added')}
className="text-gray-400 hover:bg-white/5 hover:text-white w-full justify-start gap-2"
> >
<Clock className="w-4 h-4 text-cyan-400 shrink-0" /> <Clock className="w-4 h-4 text-cyan-400 shrink-0" />
<span className="truncate">Recently Added</span> <span className="truncate">Recently Added</span>
@@ -260,13 +256,13 @@ export default function AppSidebar({
</SidebarGroup> </SidebarGroup>
</SidebarContent> </SidebarContent>
<SidebarFooter className="p-2"> <SidebarFooter className="p-2 space-y-1">
{/* Theme Toggle */} {/* Theme Toggle */}
<Button <Button
variant="ghost" variant="ghost"
size="sm" size="sm"
onClick={toggleTheme} onClick={toggleTheme}
className="w-full justify-start gap-2 text-gray-400 hover:text-white hover:bg-white/5" className="w-full justify-start gap-2 text-sidebar-foreground/60 hover:text-sidebar-foreground hover:bg-sidebar-accent"
> >
{theme === 'dark' ? ( {theme === 'dark' ? (
<> <>
@@ -275,7 +271,7 @@ export default function AppSidebar({
</> </>
) : ( ) : (
<> <>
<Moon className="w-4 h-4 text-indigo-400" /> <Moon className="w-4 h-4 text-sidebar-foreground/60" />
<span>Dark Mode</span> <span>Dark Mode</span>
</> </>
)} )}
@@ -283,7 +279,7 @@ export default function AppSidebar({
{/* User Profile */} {/* User Profile */}
{user ? ( {user ? (
<div className="flex items-center gap-3 px-2 py-2 rounded-lg bg-white/5 mt-2"> <div className="flex items-center gap-3 px-2 py-2 rounded-lg bg-sidebar-accent">
<Avatar className="w-8 h-8"> <Avatar className="w-8 h-8">
<AvatarImage src={user.avatar} alt={user.name} /> <AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="bg-[#e8466c]/20 text-[#e8466c] text-xs"> <AvatarFallback className="bg-[#e8466c]/20 text-[#e8466c] text-xs">
@@ -295,20 +291,20 @@ export default function AppSidebar({
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{user.name}</p> <p className="text-sm font-medium text-sidebar-foreground truncate">{user.name}</p>
<p className="text-xs text-gray-500 truncate">{user.email}</p> <p className="text-xs text-sidebar-foreground/50 truncate">{user.email}</p>
</div> </div>
</div> </div>
) : ( ) : (
<div className="flex items-center gap-3 px-2 py-2 rounded-lg bg-white/5 mt-2"> <div className="flex items-center gap-3 px-2 py-2 rounded-lg bg-sidebar-accent">
<Avatar className="w-8 h-8"> <Avatar className="w-8 h-8">
<AvatarFallback className="bg-[#e8466c]/20 text-[#e8466c]"> <AvatarFallback className="bg-[#e8466c]/20 text-[#e8466c]">
<User className="w-4 h-4" /> <User className="w-4 h-4" />
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white">Guest</p> <p className="text-sm font-medium text-sidebar-foreground">Guest</p>
<p className="text-xs text-gray-500">Not logged in</p> <p className="text-xs text-sidebar-foreground/50">Not logged in</p>
</div> </div>
</div> </div>
)} )}
@@ -318,7 +314,7 @@ export default function AppSidebar({
variant="ghost" variant="ghost"
size="sm" size="sm"
onClick={handleLogout} onClick={handleLogout}
className="w-full justify-start gap-2 text-gray-400 hover:text-red-400 hover:bg-red-500/10 mt-2" className="w-full justify-start gap-2 text-sidebar-foreground/60 hover:text-red-400 hover:bg-red-500/10"
> >
<LogOut className="w-4 h-4" /> <LogOut className="w-4 h-4" />
<span>Logout</span> <span>Logout</span>
+1 -1
View File
@@ -7,7 +7,7 @@ interface LoadingProps {
export default function Loading({ message = 'Loading...' }: LoadingProps) { export default function Loading({ message = 'Loading...' }: LoadingProps) {
return ( return (
<div className="flex flex-col items-center justify-center py-20 text-muted-foreground"> <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
<Loader2 className="animate-spin h-12 w-12 text-[#6d28d9] mb-4" /> <Loader2 className="animate-spin h-12 w-12 text-[#e8466c] mb-4" />
<p className="text-lg font-bold">{message}</p> <p className="text-lg font-bold">{message}</p>
</div> </div>
); );
+42 -42
View File
@@ -99,7 +99,7 @@
--mv-accent-light: #f47298; --mv-accent-light: #f47298;
/* Custom gradient colors */ /* Custom gradient colors */
--gradient-purple: linear-gradient(135deg, #6d28d9 0%, #8b5cf6 50%, #a78bfa 100%); --gradient-purple: linear-gradient(135deg, #e8466c 0%, #f47298 50%, #f9a8c9 100%);
--gradient-blue: linear-gradient(135deg, #3b82f6 0%, #60a5fa 50%, #93c5fd 100%); --gradient-blue: linear-gradient(135deg, #3b82f6 0%, #60a5fa 50%, #93c5fd 100%);
--gradient-green: linear-gradient(135deg, #22c55e 0%, #4ade80 50%, #86efac 100%); --gradient-green: linear-gradient(135deg, #22c55e 0%, #4ade80 50%, #86efac 100%);
--gradient-yellow: linear-gradient(135deg, #eab308 0%, #facc15 50%, #fde047 100%); --gradient-yellow: linear-gradient(135deg, #eab308 0%, #facc15 50%, #fde047 100%);
@@ -107,56 +107,56 @@
} }
.dark { .dark {
--background: oklch(0.12 0.01 264); --background: oklch(0.145 0.005 35);
--foreground: oklch(0.985 0 0); --foreground: oklch(0.82 0.008 35);
--card: oklch(0.18 0.02 264); --card: oklch(0.17 0.005 35);
--card-foreground: oklch(0.985 0 0); --card-foreground: oklch(0.82 0.008 35);
--popover: oklch(0.18 0.02 264); --popover: oklch(0.17 0.005 35);
--popover-foreground: oklch(0.985 0 0); --popover-foreground: oklch(0.82 0.008 35);
--primary: oklch(0.922 0 0); --primary: oklch(0.82 0.008 35);
--primary-foreground: oklch(0.205 0 0); --primary-foreground: oklch(0.145 0.005 35);
--secondary: oklch(0.269 0.01 264); --secondary: oklch(0.21 0.005 35);
--secondary-foreground: oklch(0.985 0 0); --secondary-foreground: oklch(0.82 0.008 35);
--muted: oklch(0.25 0.01 264); --muted: oklch(0.19 0.005 35);
--muted-foreground: oklch(0.708 0 0); --muted-foreground: oklch(0.55 0.01 35);
--accent: oklch(0.269 0.01 264); --accent: oklch(0.21 0.005 35);
--accent-foreground: oklch(0.985 0 0); --accent-foreground: oklch(0.82 0.008 35);
--destructive: oklch(0.704 0.191 22.216); --destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.985 0 0 / 15%); --border: oklch(0.82 0.008 35 / 10%);
--input: oklch(0.985 0 0 / 20%); --input: oklch(0.82 0.008 35 / 15%);
--ring: oklch(0.556 0 0); --ring: oklch(0.55 0 0);
--chart-1: oklch(0.87 0 0); --chart-1: oklch(0.7 0.08 35);
--chart-2: oklch(0.556 0 0); --chart-2: oklch(0.55 0.04 35);
--chart-3: oklch(0.439 0 0); --chart-3: oklch(0.4 0.02 35);
--chart-4: oklch(0.371 0 0); --chart-4: oklch(0.3 0.015 35);
--chart-5: oklch(0.269 0 0); --chart-5: oklch(0.2 0.01 35);
--sidebar: oklch(0.18 0.02 264); --sidebar: oklch(0.125 0.005 35);
--sidebar-foreground: oklch(0.985 0 0); --sidebar-foreground: oklch(0.82 0.008 35);
--sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary: oklch(0.55 0.22 0);
--sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.269 0 0); --sidebar-accent: oklch(0.19 0.005 35);
--sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-accent-foreground: oklch(0.82 0.008 35);
--sidebar-border: oklch(0.985 0 0 / 10%); --sidebar-border: oklch(0.82 0.008 35 / 8%);
--sidebar-ring: oklch(0.556 0 0); --sidebar-ring: oklch(0.55 0 0);
/* MediaVault accent color - pink/coral */ /* MediaVault accent color - pink/coral */
--mv-accent: #e8466c; --mv-accent: #e8466c;
--mv-accent-hover: #d13d60; --mv-accent-hover: #d13d60;
--mv-accent-light: #f47298; --mv-accent-light: #f47298;
/* Custom gradient colors for dark mode - more vibrant */ /* Custom gradient colors for dark mode - softer on eyes */
--gradient-purple: linear-gradient(135deg, #7c3aed 0%, #8b5cf6 50%, #a78bfa 100%); --gradient-purple: linear-gradient(135deg, #e8466c 0%, #f47298 50%, #f9a8c9 100%);
--gradient-blue: linear-gradient(135deg, #2563eb 0%, #3b82f6 50%, #60a5fa 100%); --gradient-blue: linear-gradient(135deg, #3b82f6 0%, #60a5fa 50%, #93c5fd 100%);
--gradient-green: linear-gradient(135deg, #16a34a 0%, #22c55e 50%, #4ade80 100%); --gradient-green: linear-gradient(135deg, #22c55e 0%, #4ade80 50%, #86efac 100%);
--gradient-yellow: linear-gradient(135deg, #ca8a04 0%, #eab308 50%, #facc15 100%); --gradient-yellow: linear-gradient(135deg, #eab308 0%, #facc15 50%, #fde047 100%);
--gradient-pink: linear-gradient(135deg, #e8466c 0%, #f47298 50%, #f9a8c9 100%); --gradient-pink: linear-gradient(135deg, #e8466c 0%, #f47298 50%, #f9a8c9 100%);
--gradient-orange: linear-gradient(135deg, #ea580c 0%, #f97316 50%, #fb923c 100%); --gradient-orange: linear-gradient(135deg, #f97316 0%, #fb923c 50%, #fbbf24 100%);
--gradient-cyan: linear-gradient(135deg, #0891b2 0%, #06b6d4 50%, #22d3ee 100%); --gradient-cyan: linear-gradient(135deg, #06b6d4 0%, #22d3ee 50%, #67e8f9 100%);
/* Background gradients for dark mode */ /* Background gradients for dark mode */
--bg-gradient-subtle: radial-gradient(circle at top right, rgba(232, 70, 108, 0.08) 0%, transparent 50%), --bg-gradient-subtle: radial-gradient(circle at top right, rgba(232, 70, 108, 0.06) 0%, transparent 50%),
radial-gradient(circle at bottom left, rgba(232, 70, 108, 0.05) 0%, transparent 50%); radial-gradient(circle at bottom left, rgba(232, 70, 108, 0.04) 0%, transparent 50%);
--bg-gradient-mesh: linear-gradient(135deg, rgba(232, 70, 108, 0.03) 0%, rgba(244, 114, 152, 0.03) 50%, rgba(249, 168, 201, 0.03) 100%); --bg-gradient-mesh: linear-gradient(135deg, rgba(232, 70, 108, 0.02) 0%, rgba(244, 114, 152, 0.02) 50%, rgba(249, 168, 201, 0.02) 100%);
} }
@layer base { @layer base {
@@ -164,7 +164,7 @@
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground transition-[background-color,border-color] duration-200;
} }
html { html {
@apply font-sans; @apply font-sans;