feat(ui): 5-Kachel-Banner ohne schwarze Loecher gefuellt, Vollstaendige Job-Tabelle mit TMDB-Beschreibungen wiederhergestellt
Ampel / ampel (push) Successful in 28s

This commit is contained in:
Hitonabi
2026-07-24 16:36:12 +02:00
parent 9b19b74d39
commit e18315814c
2 changed files with 273 additions and 85 deletions
+75 -59
View File
@@ -1,4 +1,4 @@
import { Disc, Film, Sparkles, CheckCircle, Shield, Zap } from 'lucide-react'
import { Disc, Sparkles, CheckCircle, Shield, Zap, Tv, HardDrive } from 'lucide-react'
import { RadialProgress } from './ui/RadialProgress'
import { TypeBadge, StatusBadge } from './ui/Badge'
import { Button } from './ui/Button'
@@ -45,14 +45,14 @@ export function HeroCinemaBanner({
onDetailClick,
onCancelClick,
}: HeroCinemaBannerProps) {
// Fall 1: Aktiver Job (Rippt oder Komprimiert)
// Fall 1: Aktiver Job (Rippt oder Komprimiert live)
if (aktiverJob) {
const isTranscoding = aktiverJob.status === 'transcoding'
const statusText = isTranscoding ? 'HandBrake Kompression' : 'MakeMKV Extraktion'
const poster = posterUrl(aktiverJob.meta)
return (
<div className="relative rounded-3xl overflow-hidden border-2 border-amber-500/50 bg-gradient-to-r from-slate-950 via-slate-900 to-indigo-950 p-6 md:p-8 shadow-[0_0_50px_-10px_rgba(245,158,11,0.3)] text-slate-100 mb-8">
<div className="relative rounded-3xl overflow-hidden border-2 border-amber-500/50 bg-gradient-to-r from-slate-950 via-slate-900 to-indigo-950 p-6 md:p-8 shadow-[0_0_50px_-10px_rgba(245,158,11,0.35)] text-slate-100 mb-8">
<div className="relative z-10 flex flex-col lg:flex-row items-center justify-between gap-8">
<div className="flex items-center gap-6">
<div className="relative flex-shrink-0">
@@ -108,70 +108,24 @@ export function HeroCinemaBanner({
)
}
// Fall 2: Keine echten gerippten Medien vorhanden -> Standby Hero Banner (Keine Fake-Filme!)
if (completedJobs.length === 0) {
return (
<div className="relative rounded-3xl overflow-hidden border border-amber-500/30 bg-gradient-to-r from-slate-950 via-[#0d121f] to-slate-950 p-6 md:p-8 shadow-[0_0_35px_-5px_rgba(245,158,11,0.15)] text-slate-100 mb-8">
<div className="relative z-10 flex flex-col md:flex-row items-center justify-between gap-6">
<div className="flex items-center gap-5">
<div className="w-24 h-24 rounded-full disc-texture shadow-2xl flex items-center justify-center p-1 animate-disc-spin border-2 border-amber-500/40 flex-shrink-0">
<div className="w-full h-full rounded-full border-2 border-dashed border-white/30 flex items-center justify-center bg-slate-950/70">
<Disc size={36} className="text-amber-400" />
</div>
</div>
<div>
<div className="flex items-center gap-2 mb-1">
<span className="px-2.5 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wider bg-emerald-500/15 text-emerald-400 border border-emerald-500/30 flex items-center gap-1">
<CheckCircle size={11} /> READY FOR DISC
</span>
<span className="text-xs text-slate-400 font-mono">System Status: Bereit</span>
</div>
<h2 className="text-2xl md:text-3xl font-extrabold tracking-tight bg-gradient-to-r from-white via-slate-100 to-amber-200 bg-clip-text text-transparent">
Rippy Cinema Studio
</h2>
<p className="text-xs text-slate-400 mt-1">
Automatische Disc-Erkennung aktiv. Lege eine 4K UHD, Blu-ray, DVD oder CD in dein Laufwerk ein.
</p>
</div>
</div>
<div className="flex items-center gap-4 text-xs font-medium text-slate-300 bg-slate-900/90 px-4 py-3 rounded-2xl border border-slate-800 flex-shrink-0">
<div className="flex items-center gap-2">
<Zap size={16} className="text-amber-400" />
<span>Gerippte Discs: <strong className="text-amber-400 font-mono text-sm">0</strong></span>
</div>
<div className="h-4 w-px bg-slate-800" />
<div className="flex items-center gap-2">
<Shield size={16} className="text-indigo-400" />
<span>MakeMKV 1:1 Lossless</span>
</div>
</div>
</div>
</div>
)
}
// Fall 3: Echte gerippte Titel vorhanden -> Zeige ECHTE gerippte Discs in der Galerie (Maximal 5 echte Jobs)
const displayJobs = completedJobs.slice(0, 5)
// Fall 2: Kein aktiver Job -> 5-Panel Kachel-Galerie VOLLSTÄNDIG ausfüllen (Zero "Löcher"!)
// Wir füllen freie Slots mit informativen Cinema-Engine-Showcase-Kacheln auf!
const realMovieTiles = completedJobs.slice(0, 4)
return (
<div className="relative rounded-3xl overflow-hidden border border-amber-500/30 bg-[#0e1322] shadow-[0_0_40px_-5px_rgba(245,158,11,0.18)] mb-8 p-4">
<div className="flex items-center justify-between px-2 mb-3">
<h3 className="text-xs font-bold uppercase tracking-wider text-amber-400 flex items-center gap-2">
<Film size={14} /> ECHTE GERIPPTE MEDIEN ({completedJobs.length})
</h3>
<span className="text-[11px] text-slate-400 font-mono">Aus deiner Rippy-Datenbank</span>
</div>
<div className="relative rounded-3xl overflow-hidden border border-amber-500/30 bg-[#0e1322] shadow-[0_0_40px_-5px_rgba(245,158,11,0.18)] mb-8 p-3">
{/* Top Subtle Amber Line */}
<div className="absolute top-0 inset-x-0 h-px bg-gradient-to-r from-transparent via-amber-500/40 to-transparent pointer-events-none" />
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3">
{displayJobs.map((job) => {
<div className="grid grid-cols-2 md:grid-cols-5 gap-3 h-44 md:h-52">
{/* Echte Medien-Kacheln aus der API */}
{realMovieTiles.map((job) => {
const poster = posterUrl(job.meta)
return (
<div
key={job.id}
onClick={() => onDetailClick && onDetailClick(job.id)}
className="relative rounded-2xl overflow-hidden group cursor-pointer border border-slate-800 hover:border-amber-500/50 transition-all bg-slate-900 aspect-[2/3] flex flex-col justify-end p-3"
className="relative rounded-2xl overflow-hidden group cursor-pointer border border-slate-800 hover:border-amber-500/50 transition-all bg-slate-900 flex flex-col justify-end p-3"
>
{poster ? (
<img
@@ -196,6 +150,68 @@ export function HeroCinemaBanner({
</div>
)
})}
{/* Center / Showcase Feature Tile: 3D Spinning Optical Disc */}
{realMovieTiles.length < 5 && (
<div className="relative rounded-2xl overflow-hidden bg-gradient-to-br from-slate-900 via-[#131929] to-slate-950 border-2 border-amber-500/40 flex items-center justify-center p-4 shadow-inner group">
<div className="w-28 h-28 md:w-32 md:h-32 rounded-full disc-texture shadow-2xl shadow-black flex items-center justify-center p-1.5 animate-disc-spin border-2 border-amber-400/60">
<div className="w-full h-full rounded-full border-2 border-dashed border-white/40 flex items-center justify-center bg-slate-950/70">
<Disc size={40} className="text-amber-400 drop-shadow-[0_0_16px_rgba(245,158,11,0.9)]" />
</div>
</div>
<div className="absolute bottom-2.5 px-3 py-0.5 rounded-full text-[10px] font-extrabold uppercase tracking-widest bg-amber-500 text-slate-950 shadow-md">
DISC ENGINE
</div>
</div>
)}
{/* Dynamic Engine Tile: Drive Status */}
{realMovieTiles.length < 4 && (
<div className="relative rounded-2xl overflow-hidden bg-gradient-to-br from-slate-900 to-indigo-950/80 border border-slate-800 flex flex-col justify-between p-4 hidden md:flex">
<div className="flex items-center gap-2 text-emerald-400 text-xs font-bold">
<CheckCircle size={14} /> DRIVE READY
</div>
<div>
<h4 className="text-sm font-bold text-slate-100">Automatische Erkennung</h4>
<p className="text-[11px] text-slate-400 mt-0.5">Lege eine Disc ein Rippy rippt sofort los.</p>
</div>
<div className="text-[10px] font-mono text-amber-400 font-bold">
4K UHD · BLU-RAY · DVD · CD
</div>
</div>
)}
{/* Dynamic Engine Tile: Media-Server Sync */}
{realMovieTiles.length < 3 && (
<div className="relative rounded-2xl overflow-hidden bg-gradient-to-br from-slate-900 to-slate-950 border border-slate-800 flex flex-col justify-between p-4 hidden md:flex">
<div className="flex items-center gap-2 text-amber-400 text-xs font-bold">
<Tv size={14} /> MEDIA SERVER
</div>
<div>
<h4 className="text-sm font-bold text-slate-100">Auto-NFO &amp; Poster</h4>
<p className="text-[11px] text-slate-400 mt-0.5">Jellyfin, Plex &amp; Kodi kompatibel.</p>
</div>
<div className="text-[10px] font-mono text-slate-400">
Auto-Scan nach Rip
</div>
</div>
)}
{/* Dynamic Engine Tile: Lossless Assurance */}
{realMovieTiles.length < 2 && (
<div className="relative rounded-2xl overflow-hidden bg-gradient-to-br from-slate-900 to-slate-950 border border-slate-800 flex flex-col justify-between p-4 hidden md:flex">
<div className="flex items-center gap-2 text-indigo-400 text-xs font-bold">
<Shield size={14} /> MakeMKV
</div>
<div>
<h4 className="text-sm font-bold text-slate-100">Lossless 1:1</h4>
<p className="text-[11px] text-slate-400 mt-0.5">Alle Tonspuren &amp; Subtitles erhalten.</p>
</div>
<div className="text-[10px] font-mono text-slate-400">
x265 HandBrake Kompression
</div>
</div>
)}
</div>
</div>
)