main: vibe coded app to feel like paper

Signed-off-by: nfel <nfilsaraee@gmail.com>
This commit is contained in:
2025-12-30 00:00:16 +03:30
parent acbaebb947
commit 91c149e92e
27 changed files with 901 additions and 8696 deletions
+2 -1
View File
@@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import { FaEdit, FaTrash, FaPlus } from 'react-icons/fa';
import { useAlbums } from '@/lib/AlbumsContext';
import { Album } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
import AdminLayout from '@/components/AdminLayout';
import AddAlbumModal from '@/components/AddAlbumModal';
import EditAlbumModal from '@/components/EditAlbumModal';
@@ -110,7 +111,7 @@ export default function AdminAlbumsPage() {
</p>
<div className="flex items-center gap-4 text-sm text-gray-400">
<span>{album.songs.length} tracks</span>
<span className="text-accent-orange font-bold">${album.price}</span>
<span className="text-accent-orange font-bold">{formatPrice(album.price)}</span>
</div>
</div>
+25 -24
View File
@@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import { FaMusic, FaShoppingCart, FaDollarSign, FaUsers } from 'react-icons/fa';
import { useAlbums } from '@/lib/AlbumsContext';
import { Purchase } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
import AdminLayout from '@/components/AdminLayout';
export default function AdminDashboard() {
@@ -51,29 +52,29 @@ export default function AdminDashboard() {
icon: FaMusic,
label: 'Total Albums',
value: stats.totalAlbums,
color: 'from-accent-cyan to-accent-cyan/80',
iconBg: 'bg-accent-cyan/20',
color: 'bg-paper-brown',
iconBg: 'bg-paper-brown/20',
},
{
icon: FaShoppingCart,
label: 'Total Purchases',
value: stats.totalPurchases,
color: 'from-accent-orange to-accent-orange/80',
iconBg: 'bg-accent-orange/20',
color: 'bg-paper-dark',
iconBg: 'bg-paper-dark/20',
},
{
icon: FaDollarSign,
label: 'Total Revenue',
value: `$${stats.totalRevenue.toFixed(2)}`,
color: 'from-green-500 to-green-600',
iconBg: 'bg-green-500/20',
value: formatPrice(stats.totalRevenue),
color: 'bg-paper-gray',
iconBg: 'bg-paper-gray/20',
},
{
icon: FaUsers,
label: 'Active Users',
value: stats.totalPurchases > 0 ? Math.ceil(stats.totalPurchases / 2) : 0,
color: 'from-purple-500 to-purple-600',
iconBg: 'bg-purple-500/20',
color: 'bg-paper-brown',
iconBg: 'bg-paper-brown/30',
},
];
@@ -82,8 +83,8 @@ export default function AdminDashboard() {
<div className="p-8">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-white mb-2">Dashboard</h1>
<p className="text-gray-400">Overview of your music store</p>
<h1 className="text-3xl font-bold text-paper-dark mb-2 border-b-4 border-paper-dark inline-block pb-1">Dashboard</h1>
<p className="text-paper-gray mt-4">Overview of your music store</p>
</div>
{/* Stats Grid */}
@@ -96,15 +97,15 @@ export default function AdminDashboard() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
className="glass-effect rounded-xl p-6 border border-white/10"
className="paper-card p-6 border-2 border-paper-brown shadow-paper"
>
<div className="flex items-center gap-4">
<div className={`p-3 ${stat.iconBg} rounded-lg`}>
<Icon className="text-2xl text-white" />
<div className={`p-3 ${stat.iconBg} border-2 border-paper-brown`}>
<Icon className="text-2xl text-paper-dark" />
</div>
<div>
<p className="text-sm text-gray-400">{stat.label}</p>
<p className="text-2xl font-bold text-white">{stat.value}</p>
<p className="text-sm text-paper-gray">{stat.label}</p>
<p className="text-2xl font-bold text-paper-dark">{stat.value}</p>
</div>
</div>
</motion.div>
@@ -117,9 +118,9 @@ export default function AdminDashboard() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4 }}
className="glass-effect rounded-xl p-6 border border-white/10"
className="paper-card p-6 border-2 border-paper-brown shadow-paper"
>
<h2 className="text-xl font-bold text-white mb-4">Recent Purchases</h2>
<h2 className="text-xl font-bold text-paper-dark mb-4 border-b-2 border-paper-dark pb-2">Recent Purchases</h2>
{stats.recentPurchases.length > 0 ? (
<div className="space-y-3">
{stats.recentPurchases.map((purchase) => {
@@ -127,25 +128,25 @@ export default function AdminDashboard() {
return (
<div
key={purchase.transactionId}
className="flex items-center justify-between p-4 bg-white/5 rounded-lg"
className="flex items-center justify-between p-4 bg-paper-light border-2 border-paper-brown/30"
>
<div>
<p className="text-white font-medium">{album?.title || 'Unknown Album'}</p>
<p className="text-sm text-gray-400">
<p className="text-paper-dark font-medium">{album?.title || 'Unknown Album'}</p>
<p className="text-sm text-paper-gray">
{new Date(purchase.purchaseDate).toLocaleDateString()} at{' '}
{new Date(purchase.purchaseDate).toLocaleTimeString()}
</p>
</div>
<div className="text-right">
<p className="text-accent-orange font-bold">${album?.price || 0}</p>
<p className="text-xs text-gray-500 font-mono">{purchase.transactionId.slice(0, 12)}...</p>
<p className="text-paper-brown font-bold">{formatPrice(album?.price || 0)}</p>
<p className="text-xs text-paper-gray font-mono">{purchase.transactionId.slice(0, 12)}...</p>
</div>
</div>
);
})}
</div>
) : (
<p className="text-gray-400 text-center py-8">No purchases yet</p>
<p className="text-paper-gray text-center py-8">No purchases yet</p>
)}
</motion.div>
</div>
+16 -16
View File
@@ -26,28 +26,28 @@ export default function AdminLoginPage() {
};
return (
<div className="min-h-screen flex items-center justify-center p-4 bg-gradient-to-br from-primary-900 via-primary-800 to-primary-900">
<div className="min-h-screen flex items-center justify-center p-4 bg-paper-light">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="w-full max-w-md"
>
<div className="glass-effect rounded-2xl p-8 border border-white/10">
<div className="paper-card p-8 border-2 border-paper-dark shadow-paper-lg">
{/* Header */}
<div className="text-center mb-8">
<div className="inline-block p-4 bg-accent-cyan/20 rounded-full mb-4">
<FaLock className="text-4xl text-accent-cyan" />
<div className="inline-block p-4 bg-paper-brown/20 border-2 border-paper-brown mb-4">
<FaLock className="text-4xl text-paper-brown" />
</div>
<h1 className="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-accent-cyan to-accent-orange mb-2">
<h1 className="text-3xl font-bold text-paper-dark mb-2 border-b-4 border-paper-dark inline-block pb-1">
Admin Panel
</h1>
<p className="text-gray-400">Sign in to manage your music store</p>
<p className="text-paper-gray mt-4">Sign in to manage your music store</p>
</div>
{/* Login Form */}
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
<label className="block text-sm font-medium text-paper-dark mb-2">
<FaUser className="inline mr-2" />
Username
</label>
@@ -56,13 +56,13 @@ export default function AdminLoginPage() {
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="admin"
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
className="w-full px-4 py-3 bg-paper-light border-2 border-paper-brown focus:border-paper-dark focus:outline-none text-paper-dark placeholder-paper-gray shadow-paper"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
<label className="block text-sm font-medium text-paper-dark mb-2">
<FaLock className="inline mr-2" />
Password
</label>
@@ -71,7 +71,7 @@ export default function AdminLoginPage() {
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
className="w-full px-4 py-3 bg-paper-light border-2 border-paper-brown focus:border-paper-dark focus:outline-none text-paper-dark placeholder-paper-gray shadow-paper"
required
/>
</div>
@@ -80,7 +80,7 @@ export default function AdminLoginPage() {
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-red-300 text-sm"
className="p-3 bg-red-100 border-2 border-red-400 text-red-700 text-sm"
>
{error}
</motion.div>
@@ -88,18 +88,18 @@ export default function AdminLoginPage() {
<button
type="submit"
className="w-full py-3 bg-gradient-to-r from-accent-cyan to-accent-cyan/80 hover:from-accent-cyan/90 hover:to-accent-cyan/70 rounded-lg font-semibold text-white transition-all glow-cyan"
className="w-full py-3 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark font-semibold text-paper-light transition-all shadow-paper-lg"
>
Sign In
</button>
</form>
{/* Demo Credentials */}
<div className="mt-6 p-4 bg-white/5 rounded-lg">
<p className="text-xs text-gray-400 text-center">
<div className="mt-6 p-4 bg-paper-brown/10 border-2 border-paper-brown">
<p className="text-xs text-paper-dark text-center">
Demo Credentials:<br />
<span className="text-accent-cyan">Username: admin</span><br />
<span className="text-accent-cyan">Password: admin123</span>
<span className="text-paper-brown font-semibold">Username: admin</span><br />
<span className="text-paper-brown font-semibold">Password: admin123</span>
</p>
</div>
</div>
+24 -23
View File
@@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import { FaDownload, FaSearch } from 'react-icons/fa';
import { useAlbums } from '@/lib/AlbumsContext';
import { Purchase } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
import AdminLayout from '@/components/AdminLayout';
export default function AdminPurchasesPage() {
@@ -42,7 +43,7 @@ export default function AdminPurchasesPage() {
date.toLocaleTimeString(),
purchase.transactionId,
album?.title || 'Unknown',
`$${album?.price || 0}`,
formatPrice(album?.price || 0),
];
});
@@ -64,16 +65,16 @@ export default function AdminPurchasesPage() {
{/* Header */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-3xl font-bold text-white mb-2">Purchase History</h1>
<p className="text-gray-400">
{purchases.length} total purchases ${totalRevenue.toFixed(2)} revenue
<h1 className="text-3xl font-bold text-paper-dark mb-2 border-b-4 border-paper-dark inline-block pb-1">Purchase History</h1>
<p className="text-paper-gray mt-4">
{purchases.length} total purchases {formatPrice(totalRevenue)} revenue
</p>
</div>
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={exportToCSV}
className="px-6 py-3 bg-gradient-to-r from-accent-orange to-accent-orange/80 hover:from-accent-orange/90 hover:to-accent-orange/70 rounded-lg font-semibold text-white transition-all glow-orange flex items-center gap-2"
className="px-6 py-3 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark font-semibold text-paper-light transition-all shadow-paper-lg flex items-center gap-2"
>
<FaDownload />
Export CSV
@@ -83,13 +84,13 @@ export default function AdminPurchasesPage() {
{/* Search */}
<div className="mb-6">
<div className="relative">
<FaSearch className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400" />
<FaSearch className="absolute left-4 top-1/2 -translate-y-1/2 text-paper-gray" />
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search by album name or transaction ID..."
className="w-full pl-12 pr-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
className="w-full pl-12 pr-4 py-3 bg-paper-light border-2 border-paper-brown focus:border-paper-dark focus:outline-none text-paper-dark placeholder-paper-gray shadow-paper"
/>
</div>
</div>
@@ -98,18 +99,18 @@ export default function AdminPurchasesPage() {
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="glass-effect rounded-xl border border-white/10 overflow-hidden"
className="paper-card border-2 border-paper-brown shadow-paper overflow-hidden"
>
{filteredPurchases.length > 0 ? (
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-white/5 border-b border-white/10">
<thead className="bg-paper-brown/20 border-b-2 border-paper-brown">
<tr>
<th className="text-left p-4 text-sm font-semibold text-gray-400">Date & Time</th>
<th className="text-left p-4 text-sm font-semibold text-gray-400">Transaction ID</th>
<th className="text-left p-4 text-sm font-semibold text-gray-400">Album</th>
<th className="text-left p-4 text-sm font-semibold text-gray-400">Genre</th>
<th className="text-right p-4 text-sm font-semibold text-gray-400">Price</th>
<th className="text-left p-4 text-sm font-semibold text-paper-dark">Date & Time</th>
<th className="text-left p-4 text-sm font-semibold text-paper-dark">Transaction ID</th>
<th className="text-left p-4 text-sm font-semibold text-paper-dark">Album</th>
<th className="text-left p-4 text-sm font-semibold text-paper-dark">Genre</th>
<th className="text-right p-4 text-sm font-semibold text-paper-dark">Price</th>
</tr>
</thead>
<tbody>
@@ -123,24 +124,24 @@ export default function AdminPurchasesPage() {
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.05 }}
className="border-b border-white/5 hover:bg-white/5 transition-colors"
className="border-b border-paper-brown/30 hover:bg-paper-sand/50 transition-colors"
>
<td className="p-4 text-white">
<td className="p-4 text-paper-dark">
<div className="text-sm">{date.toLocaleDateString()}</div>
<div className="text-xs text-gray-500">{date.toLocaleTimeString()}</div>
<div className="text-xs text-paper-gray">{date.toLocaleTimeString()}</div>
</td>
<td className="p-4">
<code className="text-xs text-accent-cyan bg-accent-cyan/10 px-2 py-1 rounded">
<code className="text-xs text-paper-brown bg-paper-brown/10 px-2 py-1 border border-paper-brown">
{purchase.transactionId}
</code>
</td>
<td className="p-4">
<div className="text-white font-medium">{album?.title || 'Unknown'}</div>
<div className="text-xs text-gray-500">{album?.songs.length} tracks</div>
<div className="text-paper-dark font-medium">{album?.title || 'Unknown'}</div>
<div className="text-xs text-paper-gray">{album?.songs.length} tracks</div>
</td>
<td className="p-4 text-gray-400 text-sm">{album?.genre}</td>
<td className="p-4 text-paper-gray text-sm">{album?.genre}</td>
<td className="p-4 text-right">
<span className="text-accent-orange font-bold">${album?.price || 0}</span>
<span className="text-paper-brown font-bold">{formatPrice(album?.price || 0)}</span>
</td>
</motion.tr>
);
@@ -150,7 +151,7 @@ export default function AdminPurchasesPage() {
</div>
) : (
<div className="p-12 text-center">
<p className="text-gray-400">
<p className="text-paper-gray">
{searchTerm ? 'No purchases found matching your search' : 'No purchases yet'}
</p>
</div>
+31 -30
View File
@@ -7,6 +7,7 @@ import { FaPlay, FaShoppingCart, FaArrowLeft, FaClock, FaMusic } from 'react-ico
import { Album, Purchase } from '@/lib/types';
import { useCart } from '@/lib/CartContext';
import { useAlbums } from '@/lib/AlbumsContext';
import { formatPrice } from '@/lib/utils';
import Header from '@/components/Header';
import CartSidebar from '@/components/CartSidebar';
import MusicPlayer from '@/components/MusicPlayer';
@@ -78,10 +79,10 @@ export default function AlbumDetailPage() {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-3xl font-bold text-white mb-4">Album not found</h1>
<h1 className="text-3xl font-bold text-paper-dark mb-4">Album not found</h1>
<button
onClick={() => router.push('/')}
className="px-6 py-3 bg-accent-cyan hover:bg-accent-cyan/80 rounded-lg text-white transition-all"
className="px-6 py-3 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark text-paper-light transition-all shadow-paper"
>
Go Back Home
</button>
@@ -112,7 +113,7 @@ export default function AlbumDetailPage() {
<div className="max-w-7xl mx-auto px-4 md:px-8 py-6">
<button
onClick={() => router.push('/')}
className="flex items-center gap-2 text-gray-400 hover:text-accent-cyan transition-colors"
className="flex items-center gap-2 text-paper-dark hover:text-paper-brown transition-colors font-medium border-b-2 border-transparent hover:border-paper-brown"
>
<FaArrowLeft />
Back to Albums
@@ -129,15 +130,15 @@ export default function AlbumDetailPage() {
transition={{ duration: 0.6 }}
className="relative"
>
<div className="aspect-square rounded-2xl overflow-hidden bg-gradient-to-br from-primary-600/50 to-primary-800/50 flex items-center justify-center border-2 border-accent-cyan/50 glow-cyan">
<div className="absolute inset-0 bg-gradient-to-br from-accent-cyan/20 to-accent-orange/20"></div>
<div className="relative z-10 text-6xl md:text-8xl font-bold text-white/20 p-8 text-center">
<div className="aspect-square overflow-hidden bg-paper-brown flex items-center justify-center border-4 border-paper-dark shadow-paper-lg">
<div className="absolute inset-0 cardboard-texture"></div>
<div className="relative z-10 text-6xl md:text-8xl font-bold text-paper-dark/20 p-8 text-center">
{album.title}
</div>
</div>
{isPurchased && (
<div className="absolute top-6 right-6 bg-accent-cyan text-white px-4 py-2 rounded-full text-sm font-semibold">
<div className="absolute top-6 right-6 bg-paper-dark text-paper-light px-4 py-2 border-2 border-paper-brown text-sm font-semibold shadow-paper">
Owned
</div>
)}
@@ -151,31 +152,31 @@ export default function AlbumDetailPage() {
className="space-y-6"
>
<div>
<p className="text-sm text-gray-400 mb-2">{album.year} {album.genre}</p>
<h1 className="text-4xl md:text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-accent-cyan to-accent-orange mb-4">
<p className="text-sm text-paper-brown mb-2 font-medium">{album.year} {album.genre}</p>
<h1 className="text-4xl md:text-5xl font-bold text-paper-dark mb-4 tracking-tight border-b-4 border-paper-dark inline-block pb-2">
{album.title}
</h1>
<p className="text-xl text-gray-300 leading-relaxed">
<p className="text-xl text-paper-dark leading-relaxed mt-6">
{album.description}
</p>
</div>
{/* Album Stats */}
<div className="flex gap-6 text-gray-400">
<div className="flex gap-6 text-paper-dark p-4 paper-card">
<div className="flex items-center gap-2">
<FaMusic className="text-accent-cyan" />
<span>{album.songs.length} tracks</span>
<FaMusic className="text-paper-brown" />
<span className="font-medium">{album.songs.length} tracks</span>
</div>
<div className="flex items-center gap-2">
<FaClock className="text-accent-cyan" />
<span>{formatTotalDuration(totalDuration)}</span>
<FaClock className="text-paper-brown" />
<span className="font-medium">{formatTotalDuration(totalDuration)}</span>
</div>
</div>
{/* Price */}
{!isPurchased && (
<div className="text-3xl font-bold text-accent-orange">
${album.price}
<div className="text-3xl font-bold text-paper-light p-4 paper-card-dark">
{formatPrice(album.price)}
</div>
)}
@@ -183,7 +184,7 @@ export default function AlbumDetailPage() {
<div className="flex gap-4 pt-4">
<button
onClick={() => setCurrentAlbum(album)}
className="flex-1 py-4 bg-accent-cyan hover:bg-accent-cyan/80 rounded-lg font-semibold text-white transition-all glow-cyan flex items-center justify-center gap-2"
className="flex-1 py-4 bg-paper-sand hover:bg-paper-gray border-2 border-paper-dark font-semibold text-paper-dark transition-all shadow-paper hover:shadow-paper-lg flex items-center justify-center gap-2"
>
<FaPlay />
{isPurchased ? 'Play Album' : 'Preview'}
@@ -193,7 +194,7 @@ export default function AlbumDetailPage() {
<>
<button
onClick={() => setAlbumToPurchase(album)}
className="flex-1 py-4 bg-accent-orange hover:bg-accent-orange/80 rounded-lg font-semibold text-white transition-all glow-orange flex items-center justify-center gap-2"
className="flex-1 py-4 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark font-semibold text-paper-light transition-all shadow-paper-lg flex items-center justify-center gap-2"
>
Buy Now
</button>
@@ -202,9 +203,9 @@ export default function AlbumDetailPage() {
disabled={inCart}
className={`py-4 px-6 ${
inCart
? 'bg-gray-700 cursor-not-allowed'
: 'bg-white/10 hover:bg-white/20 border border-white/20'
} rounded-lg font-semibold text-white transition-all flex items-center justify-center gap-2`}
? 'bg-paper-gray cursor-not-allowed opacity-50'
: 'bg-paper-light hover:bg-paper-sand border-2 border-paper-brown'
} font-semibold text-paper-dark transition-all flex items-center justify-center gap-2 shadow-paper`}
>
<FaShoppingCart />
{inCart ? 'In Cart' : 'Add to Cart'}
@@ -222,9 +223,9 @@ export default function AlbumDetailPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="glass-effect rounded-2xl p-8"
className="paper-card p-8 cardboard-texture"
>
<h2 className="text-2xl font-bold text-white mb-6">Track List</h2>
<h2 className="text-2xl font-bold text-paper-dark mb-6 border-b-2 border-paper-dark pb-2">Track List</h2>
<div className="space-y-2">
{album.songs.map((song, index) => (
<motion.div
@@ -232,29 +233,29 @@ export default function AlbumDetailPage() {
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.4, delay: index * 0.05 }}
className="flex items-center justify-between p-4 rounded-lg hover:bg-white/5 transition-colors group cursor-pointer"
className="flex items-center justify-between p-4 hover:bg-paper-sand border-2 border-transparent hover:border-paper-brown transition-all group cursor-pointer"
onClick={() => setCurrentAlbum(album)}
>
<div className="flex items-center gap-4 flex-1">
<span className="text-gray-500 font-mono text-sm w-8">
<span className="text-paper-gray font-mono text-sm w-8">
{String(index + 1).padStart(2, '0')}
</span>
<div className="flex-1">
<h3 className="text-white font-medium group-hover:text-accent-cyan transition-colors">
<h3 className="text-paper-dark font-medium group-hover:font-bold transition-all">
{song.title}
</h3>
</div>
</div>
<div className="flex items-center gap-6">
{!isPurchased && (
<span className="text-xs text-accent-orange px-2 py-1 bg-accent-orange/20 rounded">
<span className="text-xs text-paper-dark px-2 py-1 bg-paper-brown/20 border border-paper-brown">
Preview
</span>
)}
<span className="text-gray-400 text-sm font-mono">
<span className="text-paper-brown text-sm font-mono">
{song.duration}
</span>
<FaPlay className="text-accent-cyan opacity-0 group-hover:opacity-100 transition-opacity" />
<FaPlay className="text-paper-dark opacity-0 group-hover:opacity-100 transition-opacity" />
</div>
</motion.div>
))}
+46 -7
View File
@@ -4,20 +4,59 @@
@layer base {
body {
@apply bg-gradient-to-br from-primary-900 via-primary-800 to-primary-900 text-white min-h-screen;
@apply bg-paper-light text-paper-dark min-h-screen;
background-image:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' /%3E%3C/filter%3E%3Crect width='100' height='100' filter='url(%23noise)' opacity='0.05'/%3E%3C/svg%3E");
}
}
@layer utilities {
.glass-effect {
@apply bg-white/10 backdrop-blur-md border border-white/20;
.paper-card {
@apply bg-paper-sand border-2 border-paper-brown shadow-paper;
}
.glow-orange {
box-shadow: 0 0 20px rgba(255, 107, 53, 0.5);
.paper-card-light {
@apply bg-paper-light border-2 border-paper-gray shadow-paper;
}
.glow-cyan {
box-shadow: 0 0 20px rgba(0, 217, 255, 0.5);
.paper-card-dark {
@apply bg-paper-brown text-paper-light border-2 border-paper-dark shadow-paper-lg;
}
.cardboard-texture {
background-image:
repeating-linear-gradient(
90deg,
transparent,
transparent 2px,
rgba(47, 41, 38, 0.03) 2px,
rgba(47, 41, 38, 0.03) 4px
),
repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(47, 41, 38, 0.03) 2px,
rgba(47, 41, 38, 0.03) 4px
);
}
.torn-edge {
position: relative;
}
.torn-edge::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 4px;
background-image:
linear-gradient(45deg, transparent 33.33%, currentColor 33.33%, currentColor 66.66%, transparent 66.66%),
linear-gradient(-45deg, transparent 33.33%, currentColor 33.33%, currentColor 66.66%, transparent 66.66%);
background-size: 8px 4px;
background-repeat: repeat-x;
opacity: 0.1;
}
}
+23 -27
View File
@@ -71,31 +71,27 @@ export default function Home() {
<main className="pt-20">
{/* Hero Section */}
<section className="min-h-[60vh] flex items-center justify-center px-4 md:px-8 relative overflow-hidden">
{/* Animated Background */}
<div className="absolute inset-0 overflow-hidden">
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-accent-cyan/10 rounded-full blur-3xl animate-pulse"></div>
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-accent-orange/10 rounded-full blur-3xl animate-pulse" style={{ animationDelay: '1s' }}></div>
</div>
<section className="min-h-[60vh] flex items-center justify-center px-4 md:px-8 relative">
<div className="relative z-10 text-center max-w-4xl mx-auto">
<h1 className="text-5xl md:text-7xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-accent-cyan via-white to-accent-orange mb-6">
Progressive Rock
<br />
Reimagined
</h1>
<p className="text-xl md:text-2xl text-gray-300 mb-8">
Explore intricate compositions and sonic landscapes
</p>
<button
onClick={() => {
const element = document.getElementById('albums');
element?.scrollIntoView({ behavior: 'smooth' });
}}
className="px-8 py-4 bg-gradient-to-r from-accent-cyan to-accent-orange hover:from-accent-cyan/80 hover:to-accent-orange/80 rounded-full font-semibold text-white transition-all glow-cyan text-lg"
>
Explore Albums
</button>
<div className="paper-card-dark p-8 md:p-12 cardboard-texture">
<h1 className="text-5xl md:text-7xl font-bold text-paper-light mb-6 tracking-tight">
Progressive Rock
<br />
Reimagined
</h1>
<p className="text-xl md:text-2xl text-paper-sand mb-8">
Explore intricate compositions and sonic landscapes
</p>
<button
onClick={() => {
const element = document.getElementById('albums');
element?.scrollIntoView({ behavior: 'smooth' });
}}
className="px-8 py-4 bg-paper-sand border-2 border-paper-dark hover:bg-paper-gray font-semibold text-paper-dark transition-all shadow-paper hover:shadow-paper-lg text-lg"
>
Explore Albums
</button>
</div>
</div>
</section>
@@ -110,12 +106,12 @@ export default function Home() {
/>
{/* Footer */}
<footer className="py-12 px-4 md:px-8 border-t border-white/10 mt-20">
<footer className="py-12 px-4 md:px-8 border-t-2 border-paper-brown mt-20">
<div className="max-w-7xl mx-auto text-center">
<p className="text-gray-400">
<p className="text-paper-dark font-medium">
&copy; {new Date().getFullYear()} Parsa. All rights reserved.
</p>
<p className="text-sm text-gray-500 mt-2">
<p className="text-sm text-paper-gray mt-2">
Progressive Rock Composer & Producer
</p>
</div>