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 -2
View File
@@ -25,9 +25,9 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
}
return (
<div className="min-h-screen bg-gradient-to-br from-primary-900 via-primary-800 to-primary-900 flex">
<div className="min-h-screen bg-paper-light flex">
<AdminSidebar />
<main className="flex-1 overflow-auto">
<main className="flex-1 overflow-auto bg-paper-sand/30">
{children}
</main>
</div>
+9 -9
View File
@@ -23,13 +23,13 @@ export default function AdminSidebar() {
];
return (
<div className="w-64 bg-primary-900/50 backdrop-blur-sm border-r border-white/10 flex flex-col">
<div className="w-64 bg-paper-sand border-r-2 border-paper-brown flex flex-col">
{/* Header */}
<div className="p-6 border-b border-white/10">
<h1 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-accent-cyan to-accent-orange">
<div className="p-6 border-b-2 border-paper-brown">
<h1 className="text-2xl font-bold text-paper-dark border-b-4 border-paper-dark inline-block pb-1">
Admin Panel
</h1>
<p className="text-sm text-gray-400 mt-1">Parsa Music Store</p>
<p className="text-sm text-paper-gray mt-3">Parsa Music Store</p>
</div>
{/* Menu */}
@@ -43,10 +43,10 @@ export default function AdminSidebar() {
key={item.path}
whileHover={{ x: 4 }}
onClick={() => router.push(item.path)}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-lg transition-all ${
className={`w-full flex items-center gap-3 px-4 py-3 border-2 transition-all ${
isActive
? 'bg-accent-cyan/20 text-accent-cyan'
: 'text-gray-300 hover:bg-white/5'
? 'bg-paper-brown text-paper-light border-paper-dark shadow-paper'
: 'text-paper-dark border-paper-brown/30 hover:bg-paper-light hover:border-paper-brown'
}`}
>
<Icon className="text-xl" />
@@ -57,11 +57,11 @@ export default function AdminSidebar() {
</nav>
{/* Logout */}
<div className="p-4 border-t border-white/10">
<div className="p-4 border-t-2 border-paper-brown">
<motion.button
whileHover={{ x: 4 }}
onClick={handleLogout}
className="w-full flex items-center gap-3 px-4 py-3 rounded-lg text-red-400 hover:bg-red-500/10 transition-all"
className="w-full flex items-center gap-3 px-4 py-3 border-2 border-red-400 text-red-700 hover:bg-red-100 transition-all"
>
<FaSignOutAlt className="text-xl" />
<span className="font-medium">Logout</span>
+22 -22
View File
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
import { FaPlay, FaShoppingCart, FaInfoCircle } from 'react-icons/fa';
import { Album } from '@/lib/types';
import { useCart } from '@/lib/CartContext';
import { formatPrice } from '@/lib/utils';
interface AlbumCardProps {
album: Album;
@@ -41,35 +42,34 @@ export default function AlbumCard({ album, isPurchased, onPlay, onPurchase }: Al
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
viewport={{ once: true }}
whileHover={{ y: -10 }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
onClick={handleCardClick}
className="glass-effect rounded-xl overflow-hidden group cursor-pointer"
className="paper-card-light overflow-hidden group cursor-pointer hover:shadow-paper-lg transition-shadow"
>
{/* Album Cover */}
<div className="relative aspect-square bg-gradient-to-br from-primary-600/50 to-primary-800/50 flex items-center justify-center overflow-hidden">
<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 font-bold text-white/20 p-8 text-center">
<div className="relative aspect-square bg-paper-brown flex items-center justify-center overflow-hidden border-b-2 border-paper-gray">
<div className="relative z-10 text-6xl font-bold text-paper-dark/20 p-8 text-center">
{album.title}
</div>
{/* Overlay on hover */}
<div className="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-all duration-300 flex items-center justify-center gap-3">
<div className="absolute inset-0 bg-paper-dark/80 opacity-0 group-hover:opacity-100 transition-all duration-300 flex items-center justify-center gap-3">
<button
onClick={(e) => {
e.stopPropagation();
onPlay(album);
}}
className="p-4 bg-accent-cyan hover:bg-accent-cyan/80 rounded-full transition-all glow-cyan"
className="p-4 bg-paper-sand hover:bg-paper-gray border-2 border-paper-dark transition-all shadow-paper"
aria-label="Play preview"
>
<FaPlay className="text-2xl text-white" />
<FaPlay className="text-2xl text-paper-dark" />
</button>
<button
onClick={(e) => handleViewDetails(e)}
className="p-4 bg-white/20 hover:bg-white/30 rounded-full transition-all"
className="p-4 bg-paper-light hover:bg-paper-sand border-2 border-paper-brown transition-all shadow-paper"
aria-label="View details"
>
<FaInfoCircle className="text-2xl text-white" />
<FaInfoCircle className="text-2xl text-paper-dark" />
</button>
{!isPurchased && (
<button
@@ -77,39 +77,39 @@ export default function AlbumCard({ album, isPurchased, onPlay, onPurchase }: Al
disabled={isInCart(album.id)}
className={`p-4 ${
isInCart(album.id)
? 'bg-gray-700 cursor-not-allowed'
: 'bg-accent-orange hover:bg-accent-orange/80 glow-orange'
} rounded-full transition-all`}
? 'bg-paper-gray border-2 border-paper-brown cursor-not-allowed opacity-50'
: 'bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark shadow-paper'
} transition-all`}
aria-label="Add to cart"
>
<FaShoppingCart className="text-2xl text-white" />
<FaShoppingCart className="text-2xl text-paper-light" />
</button>
)}
</div>
{/* Purchased Badge */}
{isPurchased && (
<div className="absolute top-4 right-4 bg-accent-cyan text-white px-3 py-1 rounded-full text-sm font-semibold">
<div className="absolute top-4 right-4 bg-paper-dark text-paper-light px-3 py-1 border-2 border-paper-brown text-sm font-semibold">
Owned
</div>
)}
</div>
{/* Album Info */}
<div className="p-6 space-y-3">
<div className="p-6 space-y-3 bg-paper-light cardboard-texture">
<div>
<h3 className="text-xl font-bold text-white group-hover:text-accent-cyan transition-colors">
<h3 className="text-xl font-bold text-paper-dark group-hover:border-b-2 group-hover:border-paper-dark transition-all inline-block">
{album.title}
</h3>
<p className="text-sm text-gray-400">{album.year} {album.genre}</p>
<p className="text-sm text-paper-gray font-medium mt-1">{album.year} {album.genre}</p>
</div>
<p className="text-gray-300 text-sm line-clamp-2">{album.description}</p>
<p className="text-paper-dark text-sm line-clamp-2">{album.description}</p>
<div className="flex items-center justify-between pt-2">
<span className="text-sm text-gray-400">{album.songs.length} tracks</span>
<div className="flex items-center justify-between pt-2 border-t-2 border-paper-gray">
<span className="text-sm text-paper-brown font-medium">{album.songs.length} tracks</span>
{!isPurchased && (
<span className="text-lg font-bold text-accent-orange">${album.price}</span>
<span className="text-lg font-bold text-paper-dark">{formatPrice(album.price)}</span>
)}
</div>
</div>
+2 -2
View File
@@ -23,10 +23,10 @@ export default function AlbumShowcase({ purchasedAlbums, onPlay, onPurchase }: A
viewport={{ once: true }}
className="text-center mb-16"
>
<h2 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">
<h2 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">
Discography
</h2>
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
<p className="text-xl text-paper-brown max-w-2xl mx-auto mt-6">
Explore a collection of progressive rock albums that push the boundaries of sound and creativity
</p>
</motion.div>
+14 -14
View File
@@ -14,7 +14,7 @@ export default function Biography() {
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
viewport={{ once: true }}
className="glass-effect rounded-2xl p-8 md:p-12"
className="paper-card p-8 md:p-12 cardboard-texture"
>
<div className="grid md:grid-cols-2 gap-12 items-center">
{/* Image Section */}
@@ -25,8 +25,8 @@ export default function Biography() {
viewport={{ once: true }}
className="relative"
>
<div className="aspect-square rounded-xl overflow-hidden bg-gradient-to-br from-accent-orange/20 to-accent-cyan/20 flex items-center justify-center border-2 border-accent-cyan/50 glow-cyan">
<div className="text-6xl md:text-8xl font-bold text-accent-cyan/30">
<div className="aspect-square bg-paper-brown flex items-center justify-center border-4 border-paper-dark shadow-paper-lg">
<div className="text-6xl md:text-8xl font-bold text-paper-dark/20">
{artistBio.name}
</div>
</div>
@@ -40,10 +40,10 @@ export default function Biography() {
transition={{ duration: 0.6, delay: 0.3 }}
viewport={{ once: true }}
>
<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-2">
<h1 className="text-4xl md:text-5xl font-bold text-paper-dark mb-2 tracking-tight border-b-4 border-paper-dark inline-block pb-1">
{artistBio.name}
</h1>
<p className="text-xl text-accent-cyan/80 mb-6">{artistBio.title}</p>
<p className="text-xl text-paper-brown mb-6 font-medium mt-4">{artistBio.title}</p>
</motion.div>
<motion.div
@@ -51,7 +51,7 @@ export default function Biography() {
whileInView={{ opacity: 1, x: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
viewport={{ once: true }}
className="space-y-4 text-gray-300 leading-relaxed"
className="space-y-4 text-paper-dark leading-relaxed"
>
{artistBio.bio.split('\n\n').map((paragraph, idx) => (
<p key={idx}>{paragraph}</p>
@@ -68,31 +68,31 @@ export default function Biography() {
>
<a
href={artistBio.socialLinks.spotify}
className="p-3 glass-effect rounded-lg hover:bg-accent-cyan/20 transition-all hover:glow-cyan"
className="p-3 bg-paper-light border-2 border-paper-brown hover:bg-paper-brown hover:border-paper-dark transition-all shadow-paper"
aria-label="Spotify"
>
<FaSpotify className="text-2xl text-accent-cyan" />
<FaSpotify className="text-2xl text-paper-dark" />
</a>
<a
href={artistBio.socialLinks.youtube}
className="p-3 glass-effect rounded-lg hover:bg-accent-orange/20 transition-all hover:glow-orange"
className="p-3 bg-paper-light border-2 border-paper-brown hover:bg-paper-brown hover:border-paper-dark transition-all shadow-paper"
aria-label="YouTube"
>
<FaYoutube className="text-2xl text-accent-orange" />
<FaYoutube className="text-2xl text-paper-dark" />
</a>
<a
href={artistBio.socialLinks.instagram}
className="p-3 glass-effect rounded-lg hover:bg-accent-cyan/20 transition-all hover:glow-cyan"
className="p-3 bg-paper-light border-2 border-paper-brown hover:bg-paper-brown hover:border-paper-dark transition-all shadow-paper"
aria-label="Instagram"
>
<FaInstagram className="text-2xl text-accent-cyan" />
<FaInstagram className="text-2xl text-paper-dark" />
</a>
<a
href="#"
className="p-3 glass-effect rounded-lg hover:bg-accent-orange/20 transition-all hover:glow-orange"
className="p-3 bg-paper-light border-2 border-paper-brown hover:bg-paper-brown hover:border-paper-dark transition-all shadow-paper"
aria-label="Apple Music"
>
<SiApplemusic className="text-2xl text-accent-orange" />
<SiApplemusic className="text-2xl text-paper-dark" />
</a>
</motion.div>
</div>
+24 -24
View File
@@ -71,7 +71,7 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-40"
className="fixed inset-0 bg-paper-dark/80 z-40"
/>
{/* Sidebar */}
@@ -80,22 +80,22 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
animate={{ x: 0 }}
exit={{ x: '100%' }}
transition={{ type: 'spring', damping: 30, stiffness: 300 }}
className="fixed right-0 top-0 bottom-0 w-full md:w-96 glass-effect border-l border-white/10 z-50 flex flex-col"
className="fixed right-0 top-0 bottom-0 w-full md:w-96 bg-paper-sand border-l-4 border-paper-dark z-50 flex flex-col cardboard-texture"
>
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-white/10">
<div className="flex items-center justify-between p-6 border-b-2 border-paper-dark">
<div className="flex items-center gap-3">
<FaShoppingCart className="text-2xl text-accent-cyan" />
<h2 className="text-2xl font-bold text-white">
<FaShoppingCart className="text-2xl text-paper-dark" />
<h2 className="text-2xl font-bold text-paper-dark">
Cart ({cartItems.length})
</h2>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-white/10 rounded-full transition-colors"
className="p-2 hover:bg-paper-brown hover:text-paper-light border-2 border-transparent hover:border-paper-dark transition-colors"
aria-label="Close cart"
>
<FaTimes className="text-xl text-gray-400" />
<FaTimes className="text-xl text-paper-dark" />
</button>
</div>
@@ -103,9 +103,9 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
<div className="flex-1 overflow-y-auto p-6">
{cartItems.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center">
<FaShoppingCart className="text-6xl text-gray-600 mb-4" />
<p className="text-gray-400 text-lg">Your cart is empty</p>
<p className="text-gray-500 text-sm mt-2">Add some albums to get started</p>
<FaShoppingCart className="text-6xl text-paper-gray mb-4" />
<p className="text-paper-dark text-lg font-medium">Your cart is empty</p>
<p className="text-paper-brown text-sm mt-2">Add some albums to get started</p>
</div>
) : (
<div className="space-y-4">
@@ -115,25 +115,25 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="glass-effect rounded-xl p-4"
className="paper-card-light p-4"
>
<div className="flex gap-4">
{/* Album Cover */}
<div className="w-20 h-20 rounded-lg bg-gradient-to-br from-accent-cyan/20 to-accent-orange/20 flex items-center justify-center flex-shrink-0">
<span className="text-xs text-white/50 font-bold text-center px-2">
<div className="w-20 h-20 bg-paper-brown border-2 border-paper-dark flex items-center justify-center flex-shrink-0">
<span className="text-xs text-paper-dark/50 font-bold text-center px-2">
{item.album.title}
</span>
</div>
{/* Album Info */}
<div className="flex-1 min-w-0">
<h3 className="text-white font-semibold truncate">
<h3 className="text-paper-dark font-semibold truncate">
{item.album.title}
</h3>
<p className="text-sm text-gray-400">
<p className="text-sm text-paper-brown">
{item.album.year} {item.album.songs.length} tracks
</p>
<p className="text-accent-orange font-bold mt-2">
<p className="text-paper-dark font-bold mt-2">
${item.album.price}
</p>
</div>
@@ -141,10 +141,10 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
{/* Remove Button */}
<button
onClick={() => removeFromCart(item.album.id)}
className="p-2 hover:bg-red-500/20 rounded-lg transition-colors self-start"
className="p-2 hover:bg-paper-brown hover:text-paper-light border-2 border-transparent hover:border-paper-dark transition-colors self-start"
aria-label="Remove from cart"
>
<FaTrash className="text-red-400" />
<FaTrash className="text-paper-dark" />
</button>
</div>
</motion.div>
@@ -155,11 +155,11 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
{/* Footer */}
{cartItems.length > 0 && (
<div className="border-t border-white/10 p-6 space-y-4">
<div className="border-t-2 border-paper-dark p-6 space-y-4">
{/* Total */}
<div className="flex items-center justify-between text-xl">
<span className="text-gray-300 font-semibold">Total</span>
<span className="text-accent-orange font-bold">
<div className="flex items-center justify-between text-xl p-4 paper-card-dark">
<span className="text-paper-light font-semibold">Total</span>
<span className="text-paper-sand font-bold">
${getCartTotal().toFixed(2)}
</span>
</div>
@@ -168,13 +168,13 @@ export default function CartSidebar({ isOpen, onClose }: CartSidebarProps) {
<div className="space-y-3">
<button
onClick={handleCheckout}
className="w-full py-4 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"
className="w-full py-4 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark font-semibold text-paper-light transition-all shadow-paper-lg"
>
Proceed to Checkout
</button>
<button
onClick={clearCart}
className="w-full py-3 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg font-semibold text-gray-300 transition-all"
className="w-full py-3 bg-paper-light hover:bg-paper-sand border-2 border-paper-brown font-semibold text-paper-dark transition-all shadow-paper"
>
Clear Cart
</button>
+13 -13
View File
@@ -23,24 +23,24 @@ export default function Header({ onCartClick }: HeaderProps) {
<motion.header
initial={{ y: -100 }}
animate={{ y: 0 }}
className="fixed top-0 left-0 right-0 z-40 glass-effect border-b border-white/10"
className="fixed top-0 left-0 right-0 z-40 bg-paper-sand border-b-4 border-paper-dark shadow-paper-lg"
>
<div className="max-w-7xl mx-auto px-4 md:px-8 py-4">
<div className="flex items-center justify-between">
{/* Logo */}
<motion.div
whileHover={{ scale: 1.05 }}
whileHover={{ scale: 1.02 }}
className="flex items-center gap-3 cursor-pointer"
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
>
<div className="p-2 bg-gradient-to-br from-accent-cyan to-accent-orange rounded-lg glow-cyan">
<FaMusic className="text-2xl text-white" />
<div className="p-2 bg-paper-dark border-2 border-paper-brown">
<FaMusic className="text-2xl text-paper-light" />
</div>
<div>
<h1 className="text-xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-accent-cyan to-accent-orange">
<h1 className="text-xl font-bold text-paper-dark tracking-tight">
Parsa
</h1>
<p className="text-xs text-gray-400">Progressive Rock</p>
<p className="text-xs text-paper-brown">Progressive Rock</p>
</div>
</motion.div>
@@ -49,13 +49,13 @@ export default function Header({ onCartClick }: HeaderProps) {
<div className="hidden md:flex items-center gap-8">
<button
onClick={() => scrollToSection('bio')}
className="text-gray-300 hover:text-accent-cyan transition-colors"
className="text-paper-dark hover:text-paper-brown transition-colors font-medium border-b-2 border-transparent hover:border-paper-brown"
>
Bio
</button>
<button
onClick={() => scrollToSection('albums')}
className="text-gray-300 hover:text-accent-cyan transition-colors"
className="text-paper-dark hover:text-paper-brown transition-colors font-medium border-b-2 border-transparent hover:border-paper-brown"
>
Albums
</button>
@@ -63,18 +63,18 @@ export default function Header({ onCartClick }: HeaderProps) {
{/* Cart Button */}
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={onCartClick}
className="relative p-3 bg-white/10 hover:bg-white/20 rounded-lg transition-all"
className="relative p-3 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark transition-all shadow-paper"
aria-label="Shopping cart"
>
<FaShoppingCart className="text-xl text-accent-cyan" />
<FaShoppingCart className="text-xl text-paper-light" />
{cartCount > 0 && (
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
className="absolute -top-1 -right-1 bg-accent-orange text-white text-xs font-bold rounded-full w-5 h-5 flex items-center justify-center"
className="absolute -top-2 -right-2 bg-paper-dark text-paper-light text-xs font-bold border-2 border-paper-brown w-6 h-6 flex items-center justify-center"
>
{cartCount}
</motion.div>
+49 -48
View File
@@ -4,6 +4,7 @@ import { useState, useRef, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { FaPlay, FaPause, FaStepBackward, FaStepForward, FaTimes, FaChevronDown, FaChevronUp } from 'react-icons/fa';
import { Album, Song } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
interface MusicPlayerProps {
album: Album | null;
@@ -115,7 +116,7 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 bg-black/90 backdrop-blur-xl z-50"
className="fixed inset-0 bg-paper-dark/90 z-50"
/>
{/* Player Modal */}
@@ -129,13 +130,13 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
<div className="w-full max-w-sm pointer-events-auto relative">
{/* Close Button - Top Right */}
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={onClose}
className="absolute -top-2 -right-2 z-10 p-3 bg-white/90 hover:bg-white rounded-full transition-colors shadow-xl"
className="absolute -top-2 -right-2 z-10 p-3 bg-paper-light hover:bg-paper-sand border-2 border-paper-dark transition-colors shadow-paper-lg"
aria-label="Close player"
>
<FaTimes className="text-xl text-primary-900" />
<FaTimes className="text-xl text-paper-dark" />
</motion.button>
{/* Album Artwork */}
@@ -143,19 +144,19 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: 0.1 }}
className="relative aspect-square rounded-2xl overflow-hidden mb-6 shadow-2xl"
className="relative aspect-square overflow-hidden mb-6 shadow-paper-lg border-4 border-paper-dark"
>
<div className="absolute inset-0 bg-gradient-to-br from-primary-500 via-primary-700 to-primary-900"></div>
<div className="absolute inset-0 bg-gradient-to-br from-accent-cyan/30 to-accent-orange/30"></div>
<div className="absolute inset-0 bg-paper-brown"></div>
<div className="absolute inset-0 cardboard-texture"></div>
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-4xl md:text-5xl font-bold text-white/30 text-center px-6">
<div className="text-4xl md:text-5xl font-bold text-paper-dark/30 text-center px-6">
{album.title}
</div>
</div>
{/* Preview Badge */}
{!isPurchased && (
<div className="absolute top-3 right-3 bg-accent-orange/90 backdrop-blur-sm text-white px-3 py-1 rounded-full text-xs font-semibold shadow-lg">
<div className="absolute top-3 right-3 bg-paper-dark text-paper-light px-3 py-1 border-2 border-paper-brown text-xs font-semibold shadow-paper">
Preview Mode
</div>
)}
@@ -166,15 +167,15 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="text-center mb-6"
className="text-center mb-6 p-4 paper-card"
>
<h2 className="text-xl md:text-2xl font-bold text-white mb-1">
<h2 className="text-xl md:text-2xl font-bold text-paper-dark mb-1">
{currentSong?.title}
</h2>
<p className="text-base text-gray-400">
<p className="text-base text-paper-brown">
{album.title}
</p>
<p className="text-xs text-gray-500 mt-1">
<p className="text-xs text-paper-gray mt-1">
Track {currentSongIndex + 1} of {album.songs.length}
</p>
</motion.div>
@@ -184,7 +185,7 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="mb-5"
className="mb-5 p-4 paper-card-light"
>
<div className="relative">
<input
@@ -194,13 +195,13 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
value={currentTime}
onChange={handleSeek}
disabled={!isPurchased}
className="w-full h-1 bg-gray-700/50 rounded-full appearance-none cursor-pointer"
className="w-full h-2 bg-paper-gray appearance-none cursor-pointer border-2 border-paper-brown"
style={{
background: `linear-gradient(to right, #00d9ff ${(currentTime / (duration || 1)) * 100}%, rgba(255,255,255,0.1) ${(currentTime / (duration || 1)) * 100}%)`,
background: `linear-gradient(to right, #5A554C ${(currentTime / (duration || 1)) * 100}%, #D9DACA ${(currentTime / (duration || 1)) * 100}%)`,
}}
/>
</div>
<div className="flex justify-between text-xs text-gray-400 mt-1.5 font-mono">
<div className="flex justify-between text-xs text-paper-dark mt-1.5 font-mono">
<span>{formatTime(currentTime)}</span>
<span>{isPurchased ? formatTime(duration) : '0:30'}</span>
</div>
@@ -211,40 +212,40 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4 }}
className="flex items-center justify-center gap-6 mb-6"
className="flex items-center justify-center gap-6 mb-6 p-4 paper-card"
>
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handlePrevious}
className="p-3 hover:bg-white/10 rounded-full transition-colors"
className="p-3 hover:bg-paper-brown hover:text-paper-light border-2 border-transparent hover:border-paper-dark transition-colors"
aria-label="Previous track"
>
<FaStepBackward className="text-xl text-white" />
<FaStepBackward className="text-xl text-paper-dark" />
</motion.button>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={togglePlay}
className="p-5 bg-paper-dark hover:bg-paper-brown border-2 border-paper-brown transition-all shadow-paper-lg"
aria-label={isPlaying ? 'Pause' : 'Play'}
>
{isPlaying ? (
<FaPause className="text-2xl text-paper-light" />
) : (
<FaPlay className="text-2xl text-paper-light ml-0.5" />
)}
</motion.button>
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={togglePlay}
className="p-5 bg-white hover:bg-gray-100 rounded-full transition-all shadow-2xl"
aria-label={isPlaying ? 'Pause' : 'Play'}
>
{isPlaying ? (
<FaPause className="text-2xl text-primary-900" />
) : (
<FaPlay className="text-2xl text-primary-900 ml-0.5" />
)}
</motion.button>
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
onClick={handleNext}
className="p-3 hover:bg-white/10 rounded-full transition-colors"
className="p-3 hover:bg-paper-brown hover:text-paper-light border-2 border-transparent hover:border-paper-dark transition-colors"
aria-label="Next track"
>
<FaStepForward className="text-xl text-white" />
<FaStepForward className="text-xl text-paper-dark" />
</motion.button>
</motion.div>
@@ -257,9 +258,9 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={() => onPurchase(album)}
className="w-full mb-3 py-3 bg-gradient-to-r from-accent-orange to-accent-orange/80 hover:from-accent-orange/90 hover:to-accent-orange/70 rounded-xl font-semibold text-white text-base transition-all shadow-xl glow-orange"
className="w-full mb-3 py-3 bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark font-semibold text-paper-light text-base transition-all shadow-paper-lg"
>
Purchase Full Album - ${album.price}
Purchase Full Album - {formatPrice(album.price)}
</motion.button>
)}
@@ -271,7 +272,7 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
>
<button
onClick={() => setShowTrackList(!showTrackList)}
className="w-full py-2.5 bg-white/5 hover:bg-white/10 rounded-lg transition-colors flex items-center justify-center gap-2 text-gray-300 text-sm"
className="w-full py-2.5 bg-paper-sand hover:bg-paper-gray border-2 border-paper-brown transition-colors flex items-center justify-center gap-2 text-paper-dark text-sm font-medium"
>
{showTrackList ? <FaChevronUp className="text-xs" /> : <FaChevronDown className="text-xs" />}
<span className="font-medium">
@@ -288,7 +289,7 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
transition={{ duration: 0.3 }}
className="overflow-hidden"
>
<div className="mt-3 max-h-52 overflow-y-auto rounded-lg bg-white/5 p-2">
<div className="mt-3 max-h-52 overflow-y-auto bg-paper-light border-2 border-paper-brown p-2">
<div className="space-y-0.5">
{album.songs.map((song, index) => (
<button
@@ -298,20 +299,20 @@ export default function MusicPlayer({ album, isPurchased, onClose, onPurchase }:
setIsPlaying(false);
setCurrentTime(0);
}}
className={`w-full text-left px-3 py-2 rounded-md transition-all ${
className={`w-full text-left px-3 py-2 transition-all border-2 ${
index === currentSongIndex
? 'bg-accent-cyan/20 text-accent-cyan'
: 'hover:bg-white/5 text-gray-300'
? 'bg-paper-brown text-paper-light border-paper-dark'
: 'hover:bg-paper-sand text-paper-dark border-transparent'
}`}
>
<div className="flex justify-between items-center">
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500 font-mono w-5">
<span className="text-xs text-paper-gray font-mono w-5">
{String(index + 1).padStart(2, '0')}
</span>
<span className="text-sm font-medium">{song.title}</span>
</div>
<span className="text-xs text-gray-500 font-mono">{song.duration}</span>
<span className="text-xs text-paper-gray font-mono">{song.duration}</span>
</div>
</button>
))}
+3 -2
View File
@@ -4,6 +4,7 @@ import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { FaTimes, FaCreditCard, FaLock } from 'react-icons/fa';
import { Album } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
interface PaymentModalProps {
album: Album | null;
@@ -137,7 +138,7 @@ export default function PaymentModal({ album, onClose, onSuccess }: PaymentModal
<div className="mb-6 p-4 bg-white/5 rounded-lg">
<h3 className="font-semibold text-white">{album.title}</h3>
<p className="text-sm text-gray-400">{album.songs.length} tracks {album.genre}</p>
<p className="text-2xl font-bold text-accent-orange mt-2">${album.price}</p>
<p className="text-2xl font-bold text-accent-orange mt-2">{formatPrice(album.price)}</p>
</div>
{/* Payment Form */}
@@ -249,7 +250,7 @@ export default function PaymentModal({ album, onClose, onSuccess }: PaymentModal
) : (
<>
<FaLock />
Complete Purchase - ${album.price}
Complete Purchase - {formatPrice(album.price)}
</>
)}
</button>
+3 -2
View File
@@ -3,6 +3,7 @@
import { motion, AnimatePresence } from 'framer-motion';
import { FaClock, FaTimes, FaDownload } from 'react-icons/fa';
import { Album, Purchase } from '@/lib/types';
import { formatPrice } from '@/lib/utils';
interface PurchaseSuccessModalProps {
show: boolean;
@@ -23,7 +24,7 @@ PURCHASE RECEIPT
Status: PENDING APPROVAL
Album: ${album.title}
Artist: Parsa
Amount: $${album.price}
Amount: ${formatPrice(album.price)}
Transaction ID: ${purchase.transactionId}
Date: ${new Date(purchase.purchaseDate).toLocaleString()}
@@ -102,7 +103,7 @@ You will receive access to this album after confirmation.
</div>
<div className="border-t border-white/10 pt-3 flex justify-between">
<span className="text-gray-400">Amount</span>
<span className="text-accent-orange font-bold text-xl">${album.price}</span>
<span className="text-accent-orange font-bold text-xl">{formatPrice(album.price)}</span>
</div>
</div>