diff --git a/leaderboard/leaderboard.py b/leaderboard/leaderboard.py index 9560de7..a216c12 100644 --- a/leaderboard/leaderboard.py +++ b/leaderboard/leaderboard.py @@ -358,17 +358,17 @@ class Leaderboard(commands.Cog): if not chunks: return await ctx.send("No users have 10,000 or more credits!") + # Send warning message first + await ctx.send("āš ļø **Note:** The global leaderboard may be slightly inaccurate due to synchronization delays.") + embeds = [] for page_num, entries in enumerate(chunks, 1): embed = discord.Embed( - title="Global Credits Leaderboard", + title="šŸ† Global Credits Leaderboard", + description="*Only showing users with 10,000+ credits*", color=await ctx.embed_color() ) - # Add server icon if available - if ctx.guild.icon: - embed.set_thumbnail(url=ctx.guild.icon.url) - description = [] start_pos = (page_num - 1) * items_per_page @@ -377,26 +377,12 @@ class Leaderboard(commands.Cog): user_id = entry.get("userId", "0") credits = entry.get("points", 0) - # Calculate percentage position - percentage = (i / len(leaderboard_data)) * 100 - - # Medal emojis for top 3 - medal = "šŸ„‡" if i == 1 else "🄈" if i == 2 else "šŸ„‰" if i == 3 else "•" - description.append( - f"`{i}.` {medal} <@{user_id}>\n" - f"ā”— šŸ’° **{humanize_number(credits)}** credits • Top **{percentage:.1f}%**" + f"`{i}.` <@{user_id}> • **{humanize_number(credits)}** credits" ) - embed.description = "\n".join(description) - - # Modern footer with stats - total_credits = sum(entry["points"] for entry in leaderboard_data) - embed.set_footer( - text=f"Page {page_num}/{len(chunks)} • {len(leaderboard_data):,} Users • {humanize_number(total_credits)} Total Credits", - icon_url=self.bot.user.display_avatar.url - ) - embed.timestamp = datetime.now(timezone.utc) + embed.description = embed.description + "\n\n" + "\n".join(description) + embed.set_footer(text=f"Page {page_num}/{len(chunks)} • Total Users: {len(leaderboard_data)}") embeds.append(embed) view = LeaderboardView(self, ctx, embeds) @@ -456,49 +442,30 @@ class Leaderboard(commands.Cog): # Debug logging log.info(f"Credits check for {member}: {credits} credits") - # Get user's rank and total users for percentage calculation + # Get user's rank leaderboard_data = await self.get_all_balances() - total_users = len(leaderboard_data) rank = next( (i for i, entry in enumerate(leaderboard_data, 1) if entry.get("userId") == str(member.id)), None ) - # Calculate percentage (top x%) - percentage = (rank / total_users * 100) if rank and total_users > 0 else None - embed = discord.Embed( - title="", # Modern design: no title needed + title="šŸ† Global Credits", color=await ctx.embed_color() ) if credits >= 10000: - # Modern stat display with emojis and clean formatting - stats = [ - f"šŸ’° **{humanize_number(credits)}** credits", - f"šŸ“Š Rank **#{humanize_number(rank)}**" if rank else "šŸ“Š Unranked", - f"šŸŽÆ Top **{percentage:.1f}%**" if percentage else "", - f"šŸ†” `{member.id}`" - ] - - embed.description = "\n".join(s for s in stats if s) # Only include non-empty stats + embed.description = ( + f"**User:** {member.mention}\n" + f"**Credits:** {humanize_number(credits)}\n" + f"**Rank:** #{humanize_number(rank) if rank else 'Unranked'}\n" + f"**ID:** {member.id}" + ) else: - embed.description = f"šŸ’° **{humanize_number(credits)}** credits\nā— *Minimum 10,000 credits needed for ranking*" + embed.description = f"{member.mention} has less than 10,000 credits ({humanize_number(credits)} total)" - # Modern avatar display - embed.set_author( - name=member.display_name, - icon_url=member.display_avatar.url - ) - - # Add a subtle footer with timestamp - embed.set_footer( - text="Global Leaderboard Stats", - icon_url=ctx.guild.icon.url if ctx.guild.icon else None - ) - embed.timestamp = datetime.now(timezone.utc) - + embed.set_thumbnail(url=member.display_avatar.url) await ctx.send(embed=embed) @globalboard.command(name="resync") diff --git a/levelup/generator/styles/default.py b/levelup/generator/styles/default.py index 48b53a3..b1a7148 100644 --- a/levelup/generator/styles/default.py +++ b/levelup/generator/styles/default.py @@ -217,19 +217,19 @@ def generate_default_profile( # Create the stats layer with glass effect stats_layer = Image.new("RGBA", desired_card_size, (0, 0, 0, 0)) - # Create a semi-transparent background for stats with modern blur effect + # Create a modern glass morphism effect for stats glass = Image.new("RGBA", desired_card_size, (0, 0, 0, 0)) glass_draw = ImageDraw.Draw(glass) - glass_draw.rounded_rectangle(stats_area, radius=20, fill=(0, 0, 0, 95)) + glass_draw.rounded_rectangle(stats_area, radius=25, fill=(255, 255, 255, 25)) # Lighter, more modern glass # Add a subtle gradient overlay for depth gradient = Image.new("RGBA", desired_card_size, (0, 0, 0, 0)) gradient_draw = ImageDraw.Draw(gradient) - for i in range(30): - opacity = int(60 * (1 - i/30)) + for i in range(40): + opacity = int(35 * (1 - i/40)) # Reduced opacity for subtler effect gradient_draw.rounded_rectangle( (stats_area[0], stats_area[1]+i, stats_area[2], stats_area[3]), - radius=20, + radius=25, fill=(255, 255, 255, opacity) ) @@ -237,13 +237,13 @@ def generate_default_profile( stats_layer = Image.alpha_composite(stats_layer, glass) stats_layer = Image.alpha_composite(stats_layer, gradient) - # Add a subtle glow border + # Add a subtle border glow border_draw = ImageDraw.Draw(stats_layer) for i in range(3): border_draw.rounded_rectangle( (stats_area[0]-i, stats_area[1]-i, stats_area[2]+i, stats_area[3]+i), - radius=20, - outline=(155, 17, 30, 100-i*30), + radius=25, + outline=(255, 255, 255, 80-i*25), # Lighter border width=1 ) @@ -256,53 +256,58 @@ def generate_default_profile( level_text = f"P{prestige} • {level_text}" # Use larger font for level display - level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 52) # Increased from 42 - level_y = stats_area[1] + 10 + level_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 56) # Increased size + level_y = stats_area[1] + 15 # Add subtle text shadow for depth shadow_offset = 2 draw.text( - (stats_area[0] + 15 + shadow_offset, level_y + shadow_offset), + (stats_area[0] + 20 + shadow_offset, level_y + shadow_offset), level_text, font=level_font, - fill=(0, 0, 0, 100) + fill=(0, 0, 0, 80) # Reduced shadow opacity ) draw.text( - (stats_area[0] + 15, level_y), + (stats_area[0] + 20, level_y), level_text, font=level_font, fill=user_color ) # Stats section with improved layout and larger fonts - title_font_size = 26 # Increased from 20 - value_font_size = 30 # Increased from 24 + title_font_size = 28 # Increased from 26 + value_font_size = 32 # Increased from 30 title_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), title_font_size) value_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), value_font_size) - spacing = 42 # Increased from 35 + spacing = 45 # Increased spacing # Starting positions - start_x = stats_area[0] + 15 - start_y = level_y + 65 # Adjusted for larger level font + start_x = stats_area[0] + 20 + start_y = level_y + 75 # Helper function for stat rendering with improved spacing def draw_stat(x_pos, y_pos, icon, title, value, color=stat_color): - # Draw icon + # Draw icon with glow effect + for offset in [(1,1), (-1,-1), (1,-1), (-1,1)]: + draw.text((x_pos + offset[0], y_pos + offset[1] + 2), icon, font=value_font, fill=(255, 255, 255, 30)) draw.text((x_pos, y_pos + 2), icon, font=value_font, fill=color) - # Draw title - title_x = x_pos + 35 # Increased spacing after icon - draw.text((title_x, y_pos), f"{title}:", font=title_font, fill=(200, 200, 200)) + + # Draw title with modern styling + title_x = x_pos + 40 # Increased spacing after icon + draw.text((title_x, y_pos), f"{title}:", font=title_font, fill=(220, 220, 220)) + # Calculate value position title_width = draw.textlength(f"{title}:", font=title_font) - # Draw value with shadow for depth - value_x = title_x + title_width + 8 # Increased spacing between title and value - draw.text((value_x + 1, y_pos + 1), value, font=value_font, fill=(0, 0, 0, 100)) + value_x = title_x + title_width + 10 # Increased spacing + + # Draw value with subtle shadow + draw.text((value_x + 1, y_pos + 1), value, font=value_font, fill=(0, 0, 0, 60)) draw.text((value_x, y_pos), value, font=value_font, fill=color) return spacing # Draw stats in two columns with better spacing left_column_x = start_x - right_column_x = stats_area[0] + 320 # Adjusted for larger text + right_column_x = stats_area[0] + 340 # Adjusted for larger text current_y = start_y # Left column stats @@ -316,48 +321,48 @@ def generate_default_profile( current_y += draw_stat(right_column_x, current_y, "šŸ’°", "Balance", f"{humanize_number(balance)} {currency_name}") current_y += draw_stat(right_column_x, current_y, "šŸ†", "Rank", f"#{humanize_number(position)}") - # Progress bar with modern design - moved down - bar_width = stats_area[2] - stats_area[0] - 30 - bar_height = 28 # Increased from 25 - bar_y = stats_area[3] - 50 # Adjusted position + # Progress bar with modern design + bar_width = stats_area[2] - stats_area[0] - 40 # Slightly narrower + bar_height = 30 # Taller bar + bar_y = stats_area[3] - 65 # Moved up slightly progress = (current_xp - previous_xp) / (next_xp - previous_xp) - # XP text above progress bar with larger font - xp_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 24) # Increased from 20 + # XP text above progress bar + xp_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 26) # Increased size xp_text = f"EXP: {humanize_number(current_xp)} / {humanize_number(next_xp)}" xp_x = start_x + (bar_width - draw.textlength(xp_text, font=xp_font)) // 2 - # Draw XP text with shadow + # Draw XP text with improved shadow draw.text( - (xp_x + 1, bar_y - 28 + 1), # Adjusted for larger font + (xp_x + 1, bar_y - 30 + 1), xp_text, font=xp_font, - fill=(0, 0, 0, 100) + fill=(0, 0, 0, 60) ) draw.text( - (xp_x, bar_y - 28), # Adjusted for larger font + (xp_x, bar_y - 30), xp_text, font=xp_font, fill=(255, 255, 255) ) - # Create progress bar background with gradient - bar_bg = Image.new("RGBA", (bar_width, bar_height), (0, 0, 0, 100)) + # Create progress bar with modern gradient + bar_bg = Image.new("RGBA", (bar_width, bar_height), (0, 0, 0, 40)) # More transparent background progress_width = max(1, int(bar_width * progress)) - bar_progress = Image.new("RGBA", (progress_width, bar_height), level_bar_color + (200,)) + bar_progress = Image.new("RGBA", (progress_width, bar_height), level_bar_color + (230,)) # Add shine effect to progress bar gradient = Image.new("RGBA", bar_progress.size, (0, 0, 0, 0)) gradient_draw = ImageDraw.Draw(gradient) for i in range(bar_height): - opacity = int(150 * (1 - abs(i - bar_height/2)/(bar_height/2))) + opacity = int(120 * (1 - abs(i - bar_height/2)/(bar_height/2))) # Reduced shine intensity gradient_draw.rectangle( (0, i, bar_progress.width, i+1), fill=(255, 255, 255, opacity) ) bar_progress = Image.alpha_composite(bar_progress, gradient) - # Round the corners + # Round the corners more bar_mask = Image.new("L", (bar_width, bar_height)) bar_mask_draw = ImageDraw.Draw(bar_mask) bar_mask_draw.rounded_rectangle((0, 0, bar_width-1, bar_height-1), radius=bar_height//2, fill=255) @@ -372,16 +377,28 @@ def generate_default_profile( stats_layer.paste(bar_bg, (start_x, bar_y), bar_bg) stats_layer.paste(bar_progress_masked, (start_x, bar_y), bar_progress_masked) - # Progress percentage below bar + # Progress percentage with improved positioning and styling percent_text = f"{int(progress * 100)}%" - percent_x = start_x + (bar_width - draw.textlength(percent_text, font=xp_font)) // 2 + percent_font = ImageFont.truetype(str(font_path or imgtools.DEFAULT_FONT), 24) # Dedicated font size + percent_width = draw.textlength(percent_text, font=percent_font) + + # Position percentage on the progress bar itself + percent_x = start_x + progress_width - (percent_width // 2) + percent_x = min(max(start_x + 10, percent_x), start_x + bar_width - percent_width - 10) # Keep within bar bounds + percent_y = bar_y + (bar_height - 24) // 2 # Center vertically in bar + + # Draw percentage with improved visibility draw.text( - (percent_x, bar_y + bar_height + 6), # Adjusted spacing + (percent_x + 1, percent_y + 1), percent_text, - font=xp_font, - fill=stat_color, - stroke_width=1, - stroke_fill=(0, 0, 0) + font=percent_font, + fill=(0, 0, 0, 80) + ) + draw.text( + (percent_x, percent_y), + percent_text, + font=percent_font, + fill=(255, 255, 255) # White text for better contrast ) # Composite the layers