feat: initialize global styles with theme variables, Tailwind configuration, and custom UI components

This commit is contained in:
Michael committed 2026-04-16 15:39:32 +02:00
1 parent 030ddfba81
commit acd9a1a2c5
6 files changed
+39 -10

No files matched your search

+5 -1
View File
@@ -15,6 +15,7 @@ import {
AlertCircle
} from 'lucide-react';
import AlertModal from './AlertModal';
import { useTheme } from '../context/ThemeContext';
interface AudioPlayerProps {
episode: Episode | null;
@@ -24,6 +25,7 @@ interface AudioPlayerProps {
export default function AudioPlayer({ episode, onClose, userId }: AudioPlayerProps) {
const { isPlaying, setIsPlaying, togglePlay } = useAudio();
const { theme } = useTheme();
const audioRef = useRef<HTMLAudioElement>(null);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
@@ -120,8 +122,10 @@ export default function AudioPlayer({ episode, onClose, userId }: AudioPlayerPro
const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
const inverseTheme = theme === 'light' ? 'dark-theme' : 'light-theme';
return (
<div className={`fixed z-[100] transition-all duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${
<div className={`fixed z-[100] transition-all duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${inverseTheme} ${
isExpanded
? 'inset-0 rounded-none'
: 'bottom-6 left-1/2 -translate-x-1/2 w-[96%] max-w-5xl rounded-[2rem] h-[88px]'
+1 -1
View File
@@ -32,7 +32,7 @@ export default function EpisodeCard({ episode, onPlay, onDetails }: EpisodeCardP
return (
<div
className="group premium-glass rounded-[var(--radius-card)] p-4 hover:bg-[var(--bg-secondary)] transition-all duration-500 border border-[var(--border-color)] hover:border-[var(--accent-primary)]/30 flex flex-col h-full cursor-pointer relative"
className="group premium-card premium-glass rounded-[var(--radius-card)] p-4 hover:bg-[var(--bg-secondary)] transition-all duration-500 border border-[var(--border-color)] hover:border-[var(--accent-primary)]/30 flex flex-col h-full cursor-pointer relative"
onClick={handleDetailsClick}
>
{/* Visual Header */}
+1 -1
View File
@@ -257,7 +257,7 @@ export default function AddPodcast() {
) : searchType === 'podcasts' && (searchQuery.length > 0 ? searchResults?.podcasts : trendingResults?.podcasts) ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 pb-32">
{(searchQuery.length > 0 ? searchResults?.podcasts : trendingResults?.podcasts).map((podcast: any) => (
<div key={podcast.id} className="group premium-glass rounded-[var(--radius-card)] overflow-hidden flex flex-col hover:bg-[var(--bg-secondary)] transition-all duration-500 border-[var(--border-color)]">
<div key={podcast.id} className="group premium-card premium-glass rounded-[var(--radius-card)] overflow-hidden flex flex-col hover:bg-[var(--bg-secondary)] transition-all duration-500 border-[var(--border-color)]">
<div className="relative aspect-[16/10] overflow-hidden">
{podcast.imageUrl ? (
<img src={podcast.imageUrl} alt={podcast.title} className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" />
+3 -3
View File
@@ -111,7 +111,7 @@ export default function Library() {
{/* Stats */}
<div className="grid grid-cols-2 gap-4 mb-10">
<div className="premium-glass p-5 rounded-[var(--radius-card)] flex items-center gap-4">
<div className="premium-card premium-glass p-5 rounded-[var(--radius-card)] flex items-center gap-4">
<div className="w-10 h-10 rounded-xl bg-[var(--accent-glow)] flex items-center justify-center text-[var(--accent-primary)] shrink-0">
<BookOpen className="w-5 h-5" />
</div>
@@ -120,7 +120,7 @@ export default function Library() {
<h3 className="text-2xl font-display font-black">{podcasts.length}</h3>
</div>
</div>
<Link to="/add" className="premium-glass p-5 rounded-[var(--radius-card)] flex items-center gap-4 group hover:bg-[var(--accent-primary)]/5 transition-all">
<Link to="/add" className="premium-card premium-glass p-5 rounded-[var(--radius-card)] flex items-center gap-4 group hover:bg-[var(--accent-primary)]/5 transition-all">
<div className="w-10 h-10 rounded-xl bg-[var(--accent-primary)] flex items-center justify-center text-white shadow-glow-indigo group-hover:scale-110 transition-transform shrink-0">
<Rss className="w-5 h-5" />
</div>
@@ -149,7 +149,7 @@ export default function Library() {
) : (
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-8 pb-10">
{podcasts.map((podcast) => (
<div key={podcast._id} className="group premium-glass rounded-[var(--radius-card)] p-6 hover:bg-[var(--bg-secondary)] transition-all duration-500 flex flex-col h-full border-[var(--border-color)]">
<div key={podcast._id} className="group premium-card premium-glass rounded-[var(--radius-card)] p-6 hover:bg-[var(--bg-secondary)] transition-all duration-500 flex flex-col h-full border-[var(--border-color)]">
<div className="flex gap-6 mb-6">
<div className="relative shrink-0">
<div className="w-24 h-24 rounded-3xl overflow-hidden shadow-2xl border border-[var(--border-color)] group-hover:scale-105 transition-transform duration-500">
+1 -1
View File
@@ -191,7 +191,7 @@ export default function Trending() {
<>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-16">
{podcasts.map((podcast, index) => (
<div key={`${skip}-${podcast.id}`} className="group premium-glass rounded-[var(--radius-card)] overflow-hidden flex flex-col hover:bg-[var(--bg-secondary)] transition-all duration-500">
<div key={`${skip}-${podcast.id}`} className="group premium-card premium-glass rounded-[var(--radius-card)] overflow-hidden flex flex-col hover:bg-[var(--bg-secondary)] transition-all duration-500">
<div className="relative aspect-[16/10] overflow-hidden">
{podcast.imageUrl ? (
<img
+28 -3
View File
@@ -14,10 +14,10 @@
--accent-glow: rgba(99, 102, 241, 0.35);
--border-color: rgba(255, 255, 255, 0.07);
--glass-blur: blur(24px) saturate(180%);
--shadow-premium: 0 25px 60px rgba(0, 0, 0, 0.6), 0 0 1px rgba(255, 255, 255, 0.1);
--input-bg: rgba(255, 255, 255, 0.03);
--radius-card: 1rem; /* 16px - Sharper, Industrial */
--radius-panel: 1.25rem; /* 20px */
--shadow-premium: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 1px rgba(255, 255, 255, 0.1);
--shadow-hover: 0 30px 70px rgba(0, 0, 0, 0.7), 0 0 1px rgba(255, 255, 255, 0.2);
}
/* ── Premium Gold (Light Theme) ── */
@@ -31,11 +31,36 @@
--accent-glow: rgba(99, 102, 241, 0.1);
--border-color: #e2e8f0; /* Soft slate border */
--glass-blur: blur(12px);
--shadow-premium: 0 10px 40px rgba(0, 0, 0, 0.04), 0 0 1px rgba(0, 0, 0, 0.05);
--shadow-premium: 0 12px 30px rgba(0, 0, 0, 0.08), 0 4px 6px rgba(0, 0, 0, 0.04);
--shadow-hover: 0 25px 50px rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.05);
--radius-card: 1rem;
--radius-panel: 1.25rem;
--input-bg: #f1f5f9;
}
/* ── Explicit Dark Theme (for nesting/inversion) ── */
.dark-theme {
--bg-primary: #080d1a;
--bg-secondary: rgba(255, 255, 255, 0.025);
--text-primary: #ffffff;
--text-secondary: #94a3b8;
--accent-primary: #6366f1;
--accent-secondary: #06b6d4;
--accent-glow: rgba(99, 102, 241, 0.35);
--border-color: rgba(255, 255, 255, 0.07);
--input-bg: rgba(255, 255, 255, 0.03);
--shadow-premium: 0 25px 60px rgba(0, 0, 0, 0.6), 0 0 1px rgba(255, 255, 255, 0.1);
--shadow-hover: 0 35px 80px rgba(0, 0, 0, 0.8), 0 0 1px rgba(255, 255, 255, 0.2);
}
}
.premium-card {
@apply transition-all duration-300;
box-shadow: var(--shadow-premium);
}
.premium-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-hover);
}
* { @apply box-border; }