![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/.cursor-server/data/User/History/-77c69b/ |
<?php
session_start();
// Handle AJAX requests
$is_ajax = isset($_GET['ajax']) && $_GET['ajax'] == '1';
if ($is_ajax) {
// For AJAX requests, wrap content in the proper container structure
echo '<div class="container" id="pageContainer">';
} else {
// Include header only for full page loads
include 'includes/header.php';
}
// Global player is included via footer.php
require_once 'config/database.php';
$pdo = getDBConnection();
// Get all users with their music and social stats (including users with no tracks)
$stmt = $pdo->prepare("
SELECT
u.id,
u.name as username,
u.email,
u.plan,
u.credits,
u.created_at as joined_date,
u.profile_image,
COUNT(mt.id) as total_tracks,
COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) as completed_tracks,
COUNT(CASE WHEN mt.status = 'processing' THEN 1 END) as processing_tracks,
COUNT(CASE WHEN mt.status = 'failed' THEN 1 END) as failed_tracks,
MAX(mt.created_at) as last_activity,
COALESCE(SUM(CASE WHEN mt.status = 'complete' THEN mt.duration ELSE 0 END), 0) as total_duration,
(SELECT COUNT(*) FROM user_follows WHERE following_id = u.id) as followers_count,
(SELECT COUNT(*) FROM user_follows WHERE follower_id = u.id) as following_count,
CASE
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 20 THEN '🎵 Pro Creator'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 10 THEN '⭐ Rising Star'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 5 THEN '🔥 Active Artist'
WHEN COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) >= 1 THEN '🎼 New Artist'
ELSE '👤 Member'
END as badge
FROM users u
LEFT JOIN music_tracks mt ON u.id = mt.user_id
GROUP BY u.id, u.name, u.email, u.plan, u.credits, u.created_at, u.profile_image
ORDER BY completed_tracks DESC, last_activity DESC
");
$stmt->execute();
$artists = $stmt->fetchAll();
// Set page variables for header
$page_title = 'Artists Directory - SoundStudioPro';
$page_description = 'Discover amazing AI music creators. Explore tracks from talented artists in our community.';
$current_page = 'artists';
?>
<style>
/* Artists-specific styles - Clean and Modern */
/* Hero Section */
.hero {
padding: 8rem 0 6rem;
text-align: center;
color: white;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0a0a0a 100%);
position: relative;
overflow: hidden;
margin-bottom: 4rem;
margin-top: 0;
}
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(102,126,234,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
opacity: 0.3;
}
.hero-content {
max-width: 90rem;
margin: 0 auto;
position: relative;
z-index: 2;
}
.hero-badge {
display: inline-block;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
color: #667eea;
padding: 1.2rem 2.4rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
margin-bottom: 2rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(102, 126, 234, 0.3);
}
.hero-title {
font-size: 5.6rem;
font-weight: 900;
line-height: 1.1;
margin-bottom: 2.4rem;
background: linear-gradient(135deg, #ffffff, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 2rem;
font-weight: 400;
margin-bottom: 4rem;
opacity: 0.9;
max-width: 70rem;
margin-left: auto;
margin-right: auto;
color: #a0aec0;
}
/* Artists Content */
.artists-content {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
padding: 6rem 0;
border-radius: 40px 40px 0 0;
margin-top: -2rem;
position: relative;
z-index: 10;
}
.artists-container {
max-width: 120rem;
margin: 0 auto;
}
/* Artists Grid */
.artists-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 3rem;
margin-bottom: 4rem;
}
.artist-card {
background: rgba(255, 255, 255, 0.05);
padding: 3rem;
border-radius: 24px;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.artist-card.has-badge {
padding-top: 4rem;
}
.artist-card:hover {
transform: translateY(-10px);
border-color: rgba(102, 126, 234, 0.3);
box-shadow: 0 30px 80px rgba(102, 126, 234, 0.2);
}
.artist-badge {
position: absolute;
top: 1rem;
right: 1rem;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 1.2rem;
font-weight: 600;
z-index: 10;
}
.artist-header {
display: flex;
align-items: center;
gap: 1.5rem;
margin-bottom: 2rem;
}
.artist-profile {
flex-shrink: 0;
}
.artist-avatar {
width: 6rem;
height: 6rem;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 2.4rem;
font-weight: 900;
color: white;
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
cursor: pointer;
transition: all 0.3s ease;
object-fit: cover;
}
.artist-avatar:hover {
transform: scale(1.1);
}
.default-avatar {
width: 6rem;
height: 6rem;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
font-size: 2.4rem;
font-weight: 900;
color: white;
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
cursor: pointer;
transition: all 0.3s ease;
}
.default-avatar:hover {
transform: scale(1.1);
}
.clickable-avatar {
cursor: pointer;
}
.artist-info {
flex: 1;
text-align: left;
}
.artist-name {
font-size: 2rem;
font-weight: 700;
color: white;
margin-bottom: 0.5rem;
}
.artist-plan {
margin-bottom: 1rem;
}
.plan-badge {
display: inline-block;
padding: 0.5rem 1rem;
border-radius: 12px;
font-size: 1.2rem;
font-weight: 600;
}
.plan-free {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
}
.plan-premium {
background: rgba(255, 193, 7, 0.2);
color: #ffc107;
}
.plan-pro {
background: rgba(72, 187, 120, 0.2);
color: #48bb78;
}
.artist-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
.stat-item {
display: flex;
align-items: center;
gap: 0.8rem;
color: #a0aec0;
font-size: 1.4rem;
}
.stat-item i {
color: #667eea;
width: 1.6rem;
}
.artist-details {
margin-bottom: 2rem;
}
.detail-row {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
font-size: 1.3rem;
color: #a0aec0;
}
.detail-row i {
color: #667eea;
margin-right: 0.5rem;
}
.track-status {
margin-bottom: 2rem;
}
.status-processing {
color: #ffc107;
font-size: 1.3rem;
margin-right: 1rem;
}
.status-failed {
color: #f56565;
font-size: 1.3rem;
}
.artist-actions {
display: flex;
gap: 1rem;
}
.view-profile-btn {
flex: 1;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 1.2rem 2rem;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.8rem;
}
.view-profile-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}
.follow-btn {
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 1.2rem 2rem;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.8rem;
}
.follow-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
.follow-btn.following {
background: linear-gradient(135deg, #48bb78, #38a169);
border-color: #48bb78;
color: white;
}
.follow-btn.following:hover {
background: linear-gradient(135deg, #38a169, #2f855a);
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(72, 187, 120, 0.4);
}
/* Loading state for buttons */
.follow-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
}
/* Animation for button state changes */
.follow-btn {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Pulse animation for following state */
@keyframes pulse-follow {
0% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(72, 187, 120, 0); }
100% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0); }
}
/* Floating hearts animation - BIGGER and more dramatic! */
@keyframes float-heart {
0% {
transform: translateY(0) rotate(0deg) scale(1);
opacity: 1;
}
50% {
transform: translateY(-50px) rotate(180deg) scale(1.2);
opacity: 0.8;
}
100% {
transform: translateY(-150px) rotate(360deg) scale(0.8);
opacity: 0;
}
}
/* Heart pulse animation */
@keyframes heart-pulse {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
/* Sparkle twinkle animation */
@keyframes sparkle-twinkle {
0%, 100% { opacity: 0; transform: scale(0.5) rotate(0deg); }
50% { opacity: 1; transform: scale(1.2) rotate(180deg); }
}
.floating-heart {
position: absolute;
pointer-events: none;
animation: float-heart 2s ease-out forwards;
filter: drop-shadow(0 0 8px rgba(255, 107, 107, 0.6));
}
.sparkle {
position: absolute;
pointer-events: none;
animation: sparkle-twinkle 1.5s ease-out forwards;
}
/* Enhanced button effects */
.follow-btn.following {
animation: pulse-follow 2s infinite, button-glow 1s ease-out;
}
@keyframes button-glow {
0% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7); }
50% { box-shadow: 0 0 20px 10px rgba(72, 187, 120, 0.4); }
100% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0); }
}
.last-activity {
font-size: 1.2rem;
color: #718096;
margin-top: 1rem;
text-align: center;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 8rem 2rem;
grid-column: 1 / -1;
}
.empty-icon {
font-size: 8rem;
margin-bottom: 2rem;
opacity: 0.5;
}
.empty-title {
font-size: 3.2rem;
color: white;
margin-bottom: 1.5rem;
font-weight: 700;
}
.empty-description {
font-size: 1.8rem;
color: #a0aec0;
margin-bottom: 3rem;
max-width: 50rem;
margin-left: auto;
margin-right: auto;
}
/* Responsive Design */
@media (max-width: 768px) {
.hero-title {
font-size: 4rem;
}
.hero-subtitle {
font-size: 1.6rem;
}
.artists-grid {
grid-template-columns: 1fr;
gap: 2rem;
}
.artist-card {
padding: 2rem 1.5rem;
}
.artist-avatar {
width: 5rem;
height: 5rem;
font-size: 2rem;
}
.artist-name {
font-size: 1.8rem;
}
.stat-item {
font-size: 1.2rem;
}
.view-profile-btn {
padding: 1rem 1.5rem;
font-size: 1.3rem;
}
.last-activity {
font-size: 1rem;
}
.container {
padding: 0 1rem;
}
.artists-content {
padding: 3rem 0;
}
}
/* EPIC INTERACTIVE HERO STYLES */
.epic-hero {
position: relative;
min-height: 100vh;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 25%, #2d1b69 50%, #1a1a1a 75%, #0a0a0a 100%);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0;
margin-top: 0;
}
/* Particle Canvas */
.particle-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.6;
}
/* Animated Background Orbs */
.animated-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.gradient-orb {
position: absolute;
border-radius: 50%;
filter: blur(60px);
animation: float 8s ease-in-out infinite;
}
.orb-1 {
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(102, 126, 234, 0.3) 0%, transparent 70%);
top: 10%;
left: 10%;
animation-delay: 0s;
}
.orb-2 {
width: 400px;
height: 400px;
background: radial-gradient(circle, rgba(118, 75, 162, 0.3) 0%, transparent 70%);
top: 60%;
right: 10%;
animation-delay: 2s;
}
.orb-3 {
width: 250px;
height: 250px;
background: radial-gradient(circle, rgba(245, 101, 101, 0.3) 0%, transparent 70%);
bottom: 20%;
left: 20%;
animation-delay: 4s;
}
.orb-4 {
width: 350px;
height: 350px;
background: radial-gradient(circle, rgba(72, 187, 120, 0.3) 0%, transparent 70%);
top: 30%;
right: 30%;
animation-delay: 6s;
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
33% { transform: translateY(-30px) rotate(120deg); }
66% { transform: translateY(20px) rotate(240deg); }
}
/* Floating 3D Cards */
.floating-cards {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
pointer-events: none;
}
.floating-card {
position: absolute;
width: 140px;
height: 180px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
cursor: pointer;
pointer-events: auto;
transition: all 0.3s ease;
animation: floatCard 6s ease-in-out infinite;
overflow: hidden;
}
.floating-card:hover {
transform: scale(1.1) rotateY(10deg);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.4);
}
.card-1 {
top: 20%;
left: 15%;
animation-delay: 0s;
}
.card-2 {
top: 15%;
right: 20%;
animation-delay: 2s;
}
.card-3 {
bottom: 25%;
left: 25%;
animation-delay: 4s;
}
@keyframes floatCard {
0%, 100% { transform: translateY(0px) rotate(0deg); }
50% { transform: translateY(-20px) rotate(5deg); }
}
.card-glow {
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #667eea, #764ba2, #f56565, #48bb78);
border-radius: 22px;
z-index: -1;
opacity: 0;
transition: opacity 0.3s ease;
}
.floating-card:hover .card-glow {
opacity: 0.6;
animation: glowPulse 2s ease-in-out infinite;
}
@keyframes glowPulse {
0%, 100% { opacity: 0.6; }
50% { opacity: 0.3; }
}
.card-content {
padding: 15px;
text-align: center;
color: white;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-avatar {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin: 0 auto 10px;
font-size: 18px;
flex-shrink: 0;
}
.card-name {
font-size: 12px;
font-weight: 600;
margin-bottom: 8px;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-stats {
font-size: 10px;
opacity: 0.8;
line-height: 1.3;
}
.card-stats .stat {
display: block;
margin-bottom: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Hero Content */
.hero-content {
position: relative;
z-index: 10;
text-align: center;
max-width: 90rem;
margin: 0 auto;
padding: 0 2rem;
}
/* Animated Badge */
.animated-badge {
display: inline-flex;
align-items: center;
gap: 1rem;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 1.5rem 2.5rem;
border-radius: 50px;
margin-bottom: 3rem;
animation: badgeFloat 4s ease-in-out infinite;
}
@keyframes badgeFloat {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.badge-icon {
font-size: 2rem;
animation: iconBounce 2s ease-in-out infinite;
}
@keyframes iconBounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
.badge-text {
font-size: 1.4rem;
font-weight: 600;
color: white;
}
.badge-count {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-weight: bold;
font-size: 1.2rem;
animation: countPulse 2s ease-in-out infinite;
}
@keyframes countPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
/* Typing Title */
.typing-title {
font-size: 5rem;
font-weight: 900;
margin-bottom: 2rem;
line-height: 1.2;
}
.title-line {
display: block;
opacity: 0;
animation: fadeInUp 1s ease forwards;
}
.title-line:nth-child(1) {
animation-delay: 0.5s;
}
.title-line:nth-child(2) {
animation-delay: 1s;
}
.title-line.highlight {
background: linear-gradient(135deg, #667eea, #764ba2, #f56565, #48bb78);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: gradientShift 3s ease-in-out infinite;
}
@keyframes gradientShift {
0%, 100% { filter: hue-rotate(0deg); }
50% { filter: hue-rotate(180deg); }
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Animated Subtitle */
.animated-subtitle {
font-size: 1.8rem;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 4rem;
line-height: 1.6;
opacity: 0;
animation: fadeInUp 1s ease forwards 1.5s;
}
.highlight-text {
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-weight: 600;
}
.pulse-text {
animation: textPulse 2s ease-in-out infinite;
}
@keyframes textPulse {
0%, 100% { opacity: 0.8; }
50% { opacity: 1; }
}
/* Live Stats */
.live-stats {
display: flex;
justify-content: center;
gap: 2rem;
margin-bottom: 4rem;
opacity: 0;
animation: fadeInUp 1s ease forwards 2s;
flex-wrap: wrap;
}
.stat-item {
text-align: center;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 2rem 1.5rem;
border-radius: 20px;
min-width: 140px;
transition: all 0.3s ease;
}
.stat-item:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
}
.stat-icon {
font-size: 2.5rem;
margin-bottom: 1rem;
animation: iconFloat 3s ease-in-out infinite;
}
@keyframes iconFloat {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
}
.stat-number {
font-size: 2.5rem;
font-weight: 900;
color: white;
margin-bottom: 0.5rem;
line-height: 1;
}
.stat-label {
font-size: 1rem;
color: rgba(255, 255, 255, 0.7);
font-weight: 500;
line-height: 1.2;
}
/* Search Container */
.search-container {
margin-bottom: 4rem;
opacity: 0;
animation: fadeInUp 1s ease forwards 2.5s;
}
.search-box {
position: relative;
max-width: 600px;
margin: 0 auto 2rem;
}
.search-icon {
position: absolute;
left: 2rem;
top: 50%;
transform: translateY(-50%);
font-size: 1.5rem;
color: rgba(255, 255, 255, 0.6);
z-index: 2;
}
.search-input {
width: 100%;
padding: 1.5rem 2rem 1.5rem 5rem;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 50px;
color: white;
font-size: 1.4rem;
transition: all 0.3s ease;
}
.search-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 30px rgba(102, 126, 234, 0.3);
}
.search-input::placeholder {
color: rgba(255, 255, 255, 0.6);
}
.search-filters {
display: flex;
justify-content: center;
gap: 1rem;
flex-wrap: wrap;
}
.filter-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 1rem 2rem;
border-radius: 25px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
}
.filter-btn:hover,
.filter-btn.active {
background: linear-gradient(135deg, #667eea, #764ba2);
border-color: transparent;
transform: translateY(-2px);
}
/* Hero Actions */
.hero-actions {
display: flex;
justify-content: center;
gap: 2rem;
opacity: 0;
animation: fadeInUp 1s ease forwards 3s;
}
.cta-btn {
display: flex;
align-items: center;
gap: 1rem;
padding: 1.5rem 3rem;
border-radius: 50px;
font-size: 1.4rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
border: none;
position: relative;
overflow: hidden;
}
.cta-btn.primary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}
.cta-btn.secondary {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
}
.cta-btn:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.4);
}
.cta-btn.primary:hover {
background: linear-gradient(135deg, #5a67d8, #6b46c1);
}
.cta-btn.secondary:hover {
background: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.5);
}
/* Scroll Indicator */
.scroll-indicator {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: rgba(255, 255, 255, 0.6);
z-index: 10;
opacity: 0;
animation: fadeInUp 1s ease forwards 3.5s;
padding: 1rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 20px;
backdrop-filter: blur(10px);
}
.scroll-arrow {
width: 2px;
height: 30px;
background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.6));
margin: 0 auto 1rem;
animation: scrollBounce 2s ease-in-out infinite;
}
@keyframes scrollBounce {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(10px); }
}
.scroll-text {
font-size: 1rem;
font-weight: 500;
white-space: nowrap;
}
/* Responsive Design */
@media (max-width: 768px) {
.typing-title {
font-size: 3rem;
}
.animated-subtitle {
font-size: 1.4rem;
}
.live-stats {
flex-direction: column;
gap: 1rem;
}
.stat-item {
min-width: auto;
}
.hero-actions {
flex-direction: column;
align-items: center;
}
.floating-card {
display: none;
}
.animated-badge {
flex-direction: column;
gap: 0.5rem;
}
}
/* Search Suggestions */
.search-suggestions {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
margin-top: 1rem;
max-height: 300px;
overflow-y: auto;
z-index: 1000;
display: none;
}
.suggestion-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 1.5rem;
cursor: pointer;
transition: all 0.3s ease;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.suggestion-item:last-child {
border-bottom: none;
}
.suggestion-item:hover {
background: rgba(102, 126, 234, 0.2);
}
.suggestion-avatar {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
font-size: 16px;
}
.suggestion-info {
flex: 1;
}
.suggestion-name {
color: white;
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 0.2rem;
}
.suggestion-badge {
color: rgba(255, 255, 255, 0.7);
font-size: 0.9rem;
}
.no-results {
padding: 2rem;
text-align: center;
color: rgba(255, 255, 255, 0.6);
font-style: italic;
}
</style>
<!-- EPIC INTERACTIVE HERO SECTION -->
<section class="epic-hero">
<!-- Particle Canvas -->
<canvas id="particleCanvas" class="particle-canvas"></canvas>
<!-- Animated Background -->
<div class="animated-bg">
<div class="gradient-orb orb-1"></div>
<div class="gradient-orb orb-2"></div>
<div class="gradient-orb orb-3"></div>
<div class="gradient-orb orb-4"></div>
</div>
<!-- Floating 3D Cards -->
<div class="floating-cards">
<div class="floating-card card-1" data-artist-id="1">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-avatar">T</div>
<div class="card-name">Test User</div>
<div class="card-stats">
<span class="stat">🎵 15 tracks</span>
<span class="stat">👥 42 followers</span>
</div>
</div>
</div>
<div class="floating-card card-2" data-artist-id="2">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-avatar">D</div>
<div class="card-name">Demo User</div>
<div class="card-stats">
<span class="stat">🎵 8 tracks</span>
<span class="stat">👥 23 followers</span>
</div>
</div>
</div>
<div class="floating-card card-3" data-artist-id="5">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-avatar">S</div>
<div class="card-name">Stephane</div>
<div class="card-stats">
<span class="stat">🎵 3 tracks</span>
<span class="stat">👥 7 followers</span>
</div>
</div>
</div>
</div>
<div class="container">
<div class="hero-content">
<!-- Animated Badge -->
<div class="hero-badge animated-badge">
<span class="badge-icon">👥</span>
<span class="badge-text">Community Members</span>
<span class="badge-count" id="liveMemberCount"><?= count($artists) ?></span>
</div>
<!-- Main Title with Typing Effect -->
<h1 class="hero-title typing-title">
<span class="title-line">Meet Our</span>
<span class="title-line highlight">Music Community</span>
</h1>
<!-- Animated Subtitle -->
<p class="hero-subtitle animated-subtitle">
Discover <span class="highlight-text">amazing AI music creators</span> from around the world.
<span class="pulse-text">Join the revolution!</span>
</p>
<!-- Live Stats Bar -->
<div class="live-stats">
<div class="stat-item">
<div class="stat-icon">🎵</div>
<div class="stat-number" id="totalTracks">0</div>
<div class="stat-label">Total Tracks</div>
</div>
<div class="stat-item">
<div class="stat-icon">👥</div>
<div class="stat-number" id="totalFollowers">0</div>
<div class="stat-label">Followers</div>
</div>
<div class="stat-item">
<div class="stat-icon">⭐</div>
<div class="stat-number" id="activeArtists">0</div>
<div class="stat-label">Active Artists</div>
</div>
<div class="stat-item">
<div class="stat-icon">🔥</div>
<div class="stat-number" id="totalDuration">0</div>
<div class="stat-label">Hours Created</div>
</div>
</div>
<!-- Interactive Search -->
<div class="search-container">
<div class="search-box">
<div class="search-icon">🔍</div>
<input type="text" id="artistSearch" placeholder="Search artists, genres, or styles..." class="search-input">
<div class="search-suggestions" id="searchSuggestions"></div>
</div>
<div class="search-filters">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="pro">Pro Creators</button>
<button class="filter-btn" data-filter="rising">Rising Stars</button>
<button class="filter-btn" data-filter="new">New Artists</button>
</div>
</div>
<!-- Call to Action -->
<div class="hero-actions">
<button class="cta-btn primary" onclick="scrollToArtists()">
<span class="btn-text">Explore Artists</span>
<span class="btn-icon">🚀</span>
</button>
<button class="cta-btn secondary" onclick="window.location.href='/auth/register.php'">
<span class="btn-text">Join Community</span>
<span class="btn-icon">✨</span>
</button>
</div>
</div>
</div>
<!-- Scroll Indicator -->
<div class="scroll-indicator">
<div class="scroll-arrow"></div>
<div class="scroll-text">Scroll to explore</div>
</div>
</section>
<!-- Artists Content -->
<section class="artists-content">
<div class="container">
<div class="artists-container">
<?php if (empty($artists)): ?>
<div class="empty-state">
<div class="empty-icon">👥</div>
<h3 class="empty-title">No community members yet</h3>
<p class="empty-description">Be the first to join our community and start creating amazing AI music!</p>
<a href="/auth/register.php" class="btn btn-primary">
<i class="fas fa-user-plus"></i> Join Community
</a>
</div>
<?php else: ?>
<div class="artists-grid">
<?php foreach ($artists as $artist): ?>
<div class="artist-card <?= !empty($artist['badge']) ? 'has-badge' : '' ?>">
<?php if (!empty($artist['badge'])): ?>
<div class="artist-badge"><?= $artist['badge'] ?></div>
<?php endif; ?>
<div class="artist-header">
<div class="artist-profile">
<?php if (!empty($artist['profile_image'])): ?>
<img src="<?= htmlspecialchars($artist['profile_image']) ?>"
alt="<?= htmlspecialchars($artist['username']) ?>"
class="artist-avatar clickable-avatar"
onclick="loadArtistProfile(<?= $artist['id'] ?>)"
title="View <?= htmlspecialchars($artist['username']) ?>'s profile"
onerror="this.parentElement.innerHTML='<div class=\'default-avatar clickable-avatar\' onclick=\'loadArtistProfile(<?= $artist['id'] ?>)\' title=\'View <?= htmlspecialchars($artist['username']) ?>\\\'s profile\\\'>' + substr(htmlspecialchars($artist['username']), 0, 1) + '</div>'">
<?php else: ?>
<div class="default-avatar clickable-avatar" onclick="loadArtistProfile(<?= $artist['id'] ?>)" title="View <?= htmlspecialchars($artist['username']) ?>'s profile"><?= substr(htmlspecialchars($artist['username']), 0, 1) ?></div>
<?php endif; ?>
</div>
<div class="artist-info">
<div class="artist-name"><?= htmlspecialchars($artist['username']) ?></div>
<div class="artist-plan">
<span class="plan-badge plan-<?= $artist['plan'] ?>"><?= ucfirst($artist['plan']) ?> Plan</span>
</div>
</div>
</div>
<div class="artist-stats">
<div class="stat-item" title="Total Tracks">
<i class="fas fa-music"></i> <?= number_format($artist['total_tracks'] ?? 0) ?>
</div>
<div class="stat-item" title="Completed Tracks">
<i class="fas fa-check-circle"></i> <?= number_format($artist['completed_tracks'] ?? 0) ?>
</div>
<div class="stat-item" title="Followers">
<i class="fas fa-users"></i> <?= number_format($artist['followers_count'] ?? 0) ?>
</div>
<div class="stat-item" title="Following">
<i class="fas fa-user-plus"></i> <?= number_format($artist['following_count'] ?? 0) ?>
</div>
</div>
<div class="artist-details">
<div class="detail-row">
<span><i class="fas fa-music"></i> <?= $artist['completed_tracks'] ?> completed</span>
<span><i class="fas fa-clock"></i> <?= floor(($artist['total_duration'] ?? 0) / 60) ?>m <?= ($artist['total_duration'] ?? 0) % 60 ?>s</span>
</div>
<div class="detail-row">
<span><i class="fas fa-calendar"></i> Joined <?= date('M Y', strtotime($artist['joined_date'])) ?></span>
<span><i class="fas fa-credit-card"></i> <?= ucfirst($artist['plan']) ?> Plan</span>
</div>
</div>
<?php if ($artist['processing_tracks'] > 0 || $artist['failed_tracks'] > 0): ?>
<div class="track-status">
<?php if ($artist['processing_tracks'] > 0): ?>
<span class="status-processing"><i class="fas fa-spinner fa-spin"></i> <?= $artist['processing_tracks'] ?> processing</span>
<?php endif; ?>
<?php if ($artist['failed_tracks'] > 0): ?>
<span class="status-failed"><i class="fas fa-exclamation-triangle"></i> <?= $artist['failed_tracks'] ?> failed</span>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="artist-actions">
<button class="btn btn-primary view-profile-btn" data-artist-id="<?= $artist['id'] ?>">
<i class="fas fa-user"></i> View Profile
</button>
<?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] != $artist['id']): ?>
<button class="btn btn-secondary follow-btn" data-artist-id="<?= $artist['id'] ?>">
<i class="fas fa-user-plus"></i> <span>Follow</span>
</button>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
<script>
// Load artist profile function
function loadArtistProfile(artistId) {
console.log('🎯 Loading artist profile for ID:', artistId);
// Show loading notification
window.showNotification('Loading artist profile...', 'info');
// Use direct navigation for now (more reliable)
const profileUrl = `/artist_profile.php?id=${artistId}`;
console.log('🎯 Navigating to:', profileUrl);
// Small delay to show the notification
setTimeout(() => {
window.location.href = profileUrl;
}, 500);
}
// Follow/Unfollow artist with cool effects
async function toggleFollow(artistId, button) {
console.log('🎯 Toggle follow for artist:', artistId);
// Add loading state
const originalContent = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Loading...';
button.disabled = true;
button.style.opacity = '0.7';
try {
const response = await fetch('/api_social.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'follow',
user_id: artistId
})
});
const result = await response.json();
if (result.success) {
// Cool success effect
button.style.transform = 'scale(1.1)';
button.style.boxShadow = '0 0 20px rgba(72, 187, 120, 0.6)';
setTimeout(() => {
button.style.transform = 'scale(1)';
button.style.boxShadow = '';
}, 300);
// Update button state
const icon = button.querySelector('i');
const text = button.querySelector('span') || button.childNodes[button.childNodes.length - 1];
if (result.action === 'followed') {
// Followed - show success animation
icon.className = 'fas fa-user-check';
text.textContent = 'Following';
button.classList.add('following');
// Add celebration effect
button.style.background = 'linear-gradient(135deg, #48bb78, #38a169)';
button.style.borderColor = '#48bb78';
// Create floating hearts effect
createFloatingHearts(button);
} else {
// Unfollowed - show neutral state
icon.className = 'fas fa-user-plus';
text.textContent = 'Follow';
button.classList.remove('following');
// Reset to default styling
button.style.background = 'rgba(255, 255, 255, 0.1)';
button.style.borderColor = 'rgba(255, 255, 255, 0.2)';
}
// Update followers count with animation
const card = button.closest('.artist-card');
const followersStat = card.querySelector('.stat-item[title="Followers"]');
if (followersStat) {
const currentCount = parseInt(followersStat.textContent.replace(/[^\d]/g, ''));
const newCount = result.action === 'followed' ? currentCount + 1 : currentCount - 1;
// Animate the count change
animateCountChange(followersStat, currentCount, newCount);
}
// Show success message
window.showNotification(result.action === 'followed' ? 'Following artist!' : 'Unfollowed artist', 'success');
} else {
// Error state
button.style.transform = 'scale(0.95)';
button.style.boxShadow = '0 0 20px rgba(245, 101, 101, 0.6)';
setTimeout(() => {
button.style.transform = 'scale(1)';
button.style.boxShadow = '';
}, 300);
window.showNotification(result.message || 'Failed to follow artist', 'error');
}
} catch (error) {
console.error('Error following artist:', error);
window.showNotification('Error following artist. Please try again.', 'error');
} finally {
// Restore button state
button.disabled = false;
button.style.opacity = '1';
}
}
// Create floating hearts effect - RANDOM BURST OF FUN!
function createFloatingHearts(element) {
const rect = element.getBoundingClientRect();
// Multiple emoji sets for variety
const emojiSets = [
['❤️', '💖', '💕', '💗', '💓', '💝', '💘', '💞'], // Hearts
['🎉', '🎊', '🎈', '🎁', '🎀', '✨', '⭐', '🌟'], // Party
['🔥', '💥', '⚡', '💫', '🌙', '☀️', '🌈', '🍀'], // Energy
['🎵', '🎶', '🎸', '🎹', '🎺', '🎻', '🥁', '🎤'], // Music
['🚀', '💎', '👑', '🏆', '🎯', '🎪', '🎨', '🎭'], // Awesome
['🍕', '🍔', '🍦', '🍩', '🍪', '🍰', '🍫', '🍭'], // Food (random fun!)
['🐱', '🐶', '🐼', '🐨', '🦄', '🐸', '🐙', '🦋'], // Animals
['🌺', '🌸', '🌼', '🌻', '🌹', '🌷', '🌱', '🌿'] // Flowers
];
// Pick a random emoji set for this follow
const currentEmojiSet = emojiSets[Math.floor(Math.random() * emojiSets.length)];
const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57', '#ff9ff3', '#54a0ff', '#5f27cd', '#ff6348', '#2ed573', '#1e90ff', '#ffa502'];
const sizes = ['20px', '28px', '36px', '44px', '52px', '60px', '68px']; // Even more variety!
// Random number of elements (8-15)
const numElements = Math.floor(Math.random() * 8) + 8;
for (let i = 0; i < numElements; i++) {
const element = document.createElement('div');
element.innerHTML = currentEmojiSet[Math.floor(Math.random() * currentEmojiSet.length)];
element.style.position = 'fixed';
element.style.left = rect.left + rect.width / 2 + 'px';
element.style.top = rect.top + rect.height / 2 + 'px';
element.style.fontSize = sizes[Math.floor(Math.random() * sizes.length)];
element.style.pointerEvents = 'none';
element.style.zIndex = '9999';
element.style.transition = 'all 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
element.style.opacity = '0';
// Random color for each element
const randomColor = colors[Math.floor(Math.random() * colors.length)];
element.style.filter = `drop-shadow(0 0 10px ${randomColor}80)`;
document.body.appendChild(element);
// Random delay and movement for each element
const randomDelay = Math.random() * 300;
const randomDistance = 150 + Math.random() * 150;
const randomAngle = Math.random() * 360;
const randomRotation = Math.random() * 1080; // Up to 3 full rotations!
const randomScale = 0.5 + Math.random() * 1.5;
setTimeout(() => {
element.style.opacity = '1';
element.style.transform = `translate(${Math.cos(randomAngle * Math.PI / 180) * randomDistance}px, ${Math.sin(randomAngle * Math.PI / 180) * randomDistance}px) rotate(${randomRotation}deg) scale(${randomScale})`;
// Random animation duration
const randomDuration = 1 + Math.random() * 1;
element.style.transition = `all ${randomDuration}s cubic-bezier(0.25, 0.46, 0.45, 0.94)`;
setTimeout(() => {
element.style.opacity = '0';
element.style.transform += ' scale(0.1)';
setTimeout(() => element.remove(), 1500);
}, randomDuration * 1000);
}, randomDelay);
}
// Random chance to add extra effects
if (Math.random() > 0.5) {
createSparkles(element);
}
if (Math.random() > 0.7) {
createConfetti(element);
}
}
// Create sparkles effect - also random!
function createSparkles(element) {
const rect = element.getBoundingClientRect();
const sparkleSets = [
['✨', '⭐', '💫', '🌟', '⚡', '💎', '🔮', '💍'], // Sparkly
['🎊', '🎉', '🎈', '🎁', '🎀', '🎪', '🎨', '🎭'], // Party
['🌙', '☀️', '🌈', '🍀', '🌺', '🌸', '🌼', '🌻'], // Nature
['🎵', '🎶', '🎸', '🎹', '🎺', '🎻', '🥁', '🎤'] // Music
];
const currentSparkleSet = sparkleSets[Math.floor(Math.random() * sparkleSets.length)];
const numSparkles = Math.floor(Math.random() * 6) + 4;
for (let i = 0; i < numSparkles; i++) {
const sparkle = document.createElement('div');
sparkle.innerHTML = currentSparkleSet[Math.floor(Math.random() * currentSparkleSet.length)];
sparkle.style.position = 'fixed';
sparkle.style.left = rect.left + Math.random() * rect.width + 'px';
sparkle.style.top = rect.top + Math.random() * rect.height + 'px';
sparkle.style.fontSize = (16 + Math.random() * 20) + 'px';
sparkle.style.pointerEvents = 'none';
sparkle.style.zIndex = '9998';
sparkle.style.opacity = '0';
sparkle.style.transition = 'all 1s ease-out';
document.body.appendChild(sparkle);
const randomDelay = Math.random() * 200;
const randomDistance = 30 + Math.random() * 70;
const randomAngle = Math.random() * 360;
setTimeout(() => {
sparkle.style.opacity = '1';
sparkle.style.transform = `translate(${Math.cos(randomAngle * Math.PI / 180) * randomDistance}px, ${Math.sin(randomAngle * Math.PI / 180) * randomDistance}px) rotate(${Math.random() * 360}deg)`;
setTimeout(() => {
sparkle.style.opacity = '0';
setTimeout(() => sparkle.remove(), 1000);
}, 1000);
}, randomDelay);
}
}
// Create confetti effect - extra random fun!
function createConfetti(element) {
const rect = element.getBoundingClientRect();
const confettiColors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57', '#ff9ff3', '#54a0ff', '#5f27cd'];
const confettiShapes = ['●', '◆', '■', '▲', '★', '♦', '♠', '♥'];
const numConfetti = Math.floor(Math.random() * 8) + 4;
for (let i = 0; i < numConfetti; i++) {
const confetti = document.createElement('div');
confetti.innerHTML = confettiShapes[Math.floor(Math.random() * confettiShapes.length)];
confetti.style.position = 'fixed';
confetti.style.left = rect.left + rect.width / 2 + 'px';
confetti.style.top = rect.top + rect.height / 2 + 'px';
confetti.style.fontSize = (12 + Math.random() * 16) + 'px';
confetti.style.color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
confetti.style.pointerEvents = 'none';
confetti.style.zIndex = '9997';
confetti.style.opacity = '0';
confetti.style.transition = 'all 2s ease-out';
document.body.appendChild(confetti);
const randomDelay = Math.random() * 400;
const randomDistance = 100 + Math.random() * 100;
const randomAngle = Math.random() * 360;
setTimeout(() => {
confetti.style.opacity = '1';
confetti.style.transform = `translate(${Math.cos(randomAngle * Math.PI / 180) * randomDistance}px, ${Math.sin(randomAngle * Math.PI / 180) * randomDistance}px) rotate(${Math.random() * 720}deg)`;
setTimeout(() => {
confetti.style.opacity = '0';
setTimeout(() => confetti.remove(), 2000);
}, 2000);
}, randomDelay);
}
}
// Animate count change
function animateCountChange(element, from, to) {
const duration = 1000;
const start = Date.now();
function update() {
const elapsed = Date.now() - start;
const progress = Math.min(elapsed / duration, 1);
// Easing function
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
const current = Math.floor(from + (to - from) * easeOutQuart);
element.innerHTML = `<i class="fas fa-users"></i> ${current.toLocaleString()}`;
if (progress < 1) {
requestAnimationFrame(update);
}
}
update();
}
// EPIC HERO JAVASCRIPT - PARTICLE SYSTEM & INTERACTIVE EFFECTS
// Particle System
class ParticleSystem {
constructor() {
this.canvas = document.getElementById('particleCanvas');
this.ctx = this.canvas.getContext('2d');
this.particles = [];
this.mouse = { x: 0, y: 0 };
this.resize();
this.init();
this.animate();
window.addEventListener('resize', () => this.resize());
window.addEventListener('mousemove', (e) => {
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
});
}
resize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
init() {
// Create particles
for (let i = 0; i < 100; i++) {
this.particles.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
size: Math.random() * 3 + 1,
opacity: Math.random() * 0.5 + 0.2,
color: ['#667eea', '#764ba2', '#f56565', '#48bb78'][Math.floor(Math.random() * 4)]
});
}
}
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.particles.forEach(particle => {
// Update position
particle.x += particle.vx;
particle.y += particle.vy;
// Wrap around edges
if (particle.x < 0) particle.x = this.canvas.width;
if (particle.x > this.canvas.width) particle.x = 0;
if (particle.y < 0) particle.y = this.canvas.height;
if (particle.y > this.canvas.height) particle.y = 0;
// Draw particle
this.ctx.beginPath();
this.ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
this.ctx.fillStyle = particle.color;
this.ctx.globalAlpha = particle.opacity;
this.ctx.fill();
// Connect nearby particles
this.particles.forEach(otherParticle => {
const dx = particle.x - otherParticle.x;
const dy = particle.y - otherParticle.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
this.ctx.beginPath();
this.ctx.moveTo(particle.x, particle.y);
this.ctx.lineTo(otherParticle.x, otherParticle.y);
this.ctx.strokeStyle = particle.color;
this.ctx.globalAlpha = (100 - distance) / 100 * 0.1;
this.ctx.lineWidth = 1;
this.ctx.stroke();
}
});
});
requestAnimationFrame(() => this.animate());
}
}
// Live Stats Calculator
function calculateLiveStats() {
const artists = <?= json_encode($artists) ?>;
let totalTracks = 0;
let totalFollowers = 0;
let activeArtists = 0;
let totalDuration = 0;
artists.forEach(artist => {
totalTracks += parseInt(artist.completed_tracks || 0);
totalFollowers += parseInt(artist.followers_count || 0);
totalDuration += parseInt(artist.total_duration || 0);
if (parseInt(artist.completed_tracks || 0) > 0) {
activeArtists++;
}
});
// Update member count
const memberCountElement = document.getElementById('liveMemberCount');
if (memberCountElement) {
memberCountElement.textContent = artists.length;
}
// Animate stats with proper formatting
animateNumber('totalTracks', totalTracks);
animateNumber('totalFollowers', totalFollowers);
animateNumber('activeArtists', activeArtists);
animateNumber('totalDuration', Math.floor(totalDuration / 3600)); // Convert to hours
}
function animateNumber(elementId, targetValue) {
const element = document.getElementById(elementId);
if (!element) return;
const startValue = 0;
const duration = 2000;
const startTime = Date.now();
function update() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
const currentValue = Math.floor(startValue + (targetValue - startValue) * easeOutQuart);
// Format number properly
element.textContent = currentValue.toLocaleString();
if (progress < 1) {
requestAnimationFrame(update);
}
}
update();
}
// Interactive Search
function initializeSearch() {
const searchInput = document.getElementById('artistSearch');
const suggestions = document.getElementById('searchSuggestions');
const artists = <?= json_encode($artists) ?>;
if (!searchInput) return;
searchInput.addEventListener('input', (e) => {
const query = e.target.value.toLowerCase();
if (query.length < 2) {
suggestions.innerHTML = '';
suggestions.style.display = 'none';
return;
}
const filteredArtists = artists.filter(artist =>
artist.username.toLowerCase().includes(query) ||
artist.badge.toLowerCase().includes(query) ||
artist.plan.toLowerCase().includes(query)
).slice(0, 5);
if (filteredArtists.length > 0) {
suggestions.innerHTML = filteredArtists.map(artist => `
<div class="suggestion-item" onclick="loadArtistProfile(${artist.id})">
<div class="suggestion-avatar">${artist.username.charAt(0)}</div>
<div class="suggestion-info">
<div class="suggestion-name">${artist.username}</div>
<div class="suggestion-badge">${artist.badge}</div>
</div>
</div>
`).join('');
suggestions.style.display = 'block';
} else {
suggestions.innerHTML = '<div class="no-results">No artists found</div>';
suggestions.style.display = 'block';
}
});
// Close suggestions when clicking outside
document.addEventListener('click', (e) => {
if (!searchInput.contains(e.target) && !suggestions.contains(e.target)) {
suggestions.style.display = 'none';
}
});
}
// Filter Buttons
function initializeFilters() {
const filterButtons = document.querySelectorAll('.filter-btn');
const artistCards = document.querySelectorAll('.artist-card');
filterButtons.forEach(button => {
button.addEventListener('click', () => {
const filter = button.getAttribute('data-filter');
// Update active button
filterButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// Filter cards
artistCards.forEach(card => {
const badge = card.querySelector('.artist-badge')?.textContent || '';
const plan = card.querySelector('.plan-badge')?.textContent || '';
let shouldShow = true;
switch (filter) {
case 'pro':
shouldShow = badge.includes('Pro Creator');
break;
case 'rising':
shouldShow = badge.includes('Rising Star');
break;
case 'new':
shouldShow = badge.includes('New Artist') || badge.includes('Active Artist');
break;
default:
shouldShow = true;
}
if (shouldShow) {
card.style.display = 'block';
card.style.animation = 'fadeInUp 0.5s ease forwards';
} else {
card.style.display = 'none';
}
});
});
});
}
// Floating Cards Interaction
function initializeFloatingCards() {
const floatingCards = document.querySelectorAll('.floating-card');
floatingCards.forEach(card => {
card.addEventListener('click', () => {
const artistId = card.getAttribute('data-artist-id');
if (artistId) {
loadArtistProfile(artistId);
}
});
// Magnetic effect
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
card.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) rotateY(${x * 0.02}deg) rotateX(${-y * 0.02}deg)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'translate(0, 0) rotateY(0deg) rotateX(0deg)';
});
});
}
// Scroll to Artists Section
function scrollToArtists() {
const artistsSection = document.querySelector('.artists-content');
if (artistsSection) {
artistsSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
// Initialize everything when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
console.log('🚀 Initializing EPIC Hero Section...');
// Initialize particle system
new ParticleSystem();
// Calculate and animate live stats
calculateLiveStats();
// Initialize search functionality
initializeSearch();
// Initialize filter buttons
initializeFilters();
// Initialize floating cards
initializeFloatingCards();
console.log('🎉 EPIC Hero Section initialized successfully!');
});
</script>
<?php
// Include footer only for full page loads
if (!$is_ajax) {
include 'includes/footer.php';
} else {
// For AJAX requests, include footer which already contains global player
include 'includes/footer.php';
echo '</div>';
}
?>