embed stuff, and made it so listfonts shows an image so users know what the fonts look like

This commit is contained in:
Lilac-Rose
2025-11-13 06:26:05 +01:00
parent 603f0e8eeb
commit a9ff9a85d1
2 changed files with 122 additions and 46 deletions

View File

@@ -61,8 +61,14 @@ class EmbedColor(commands.Cog):
db.commit()
db.close()
await interaction.response.send_message(f"Your embed color has been set to `{hex_color}`")
embed = discord.Embed(
title="✅ Embed Color Updated",
description=f"Your embed color has been set to `{hex_color}`.\nHere's how it looks!",
color=discord.Color(int(hex_color[1:], 16))
)
await interaction.response.send_message(embed=embed)
@embed_group.command(name="view", description="View your current embed color")
async def view_color(self, interaction: discord.Interaction):
color = self.get_user_color(interaction.user)

View File

@@ -24,7 +24,7 @@ class Profiles(commands.Cog):
self.bot = bot
setup_db()
@app_commands.command(name="listfonts", description="List all avaliable fonts for profiles.")
@app_commands.command(name="listfonts", description="List all available fonts with a visual preview.")
async def list_fonts_cmd(self, interaction: discord.Interaction):
await interaction.response.defer(thinking=True)
@@ -32,7 +32,66 @@ class Profiles(commands.Cog):
if not fonts:
await interaction.followup.send("No fonts found in the fonts folder.")
return
await interaction.followup.send("**Avaliable Fonts:**\n" + "\n".join(f"- `{f}`" for f in fonts))
async def generate_font_preview():
def _generate():
font_sample_text = "The quick brown fox jumps over the lazy dog"
margin = 40
spacing = 90
img_width = 1600
img_height = max(400, len(fonts) * spacing + 60)
img = Image.new("RGB", (img_width, img_height), "#1e1e1e")
draw = ImageDraw.Draw(img)
y = margin
for name in fonts:
font_path_ttf = os.path.join(FONTS_PATH, f"{name}.ttf")
font_path_otf = os.path.join(FONTS_PATH, f"{name}.otf")
try:
if os.path.exists(font_path_ttf):
preview_font = ImageFont.truetype(font_path_ttf, 36)
elif os.path.exists(font_path_otf):
preview_font = ImageFont.truetype(font_path_otf, 36)
else:
preview_font = ImageFont.load_default()
except Exception:
preview_font = ImageFont.load_default()
# Slightly smaller font name for balance
try:
if os.path.exists(font_path_ttf):
name_font = ImageFont.truetype(font_path_ttf, 32)
elif os.path.exists(font_path_otf):
name_font = ImageFont.truetype(font_path_otf, 32)
else:
name_font = ImageFont.load_default()
except Exception:
name_font = ImageFont.load_default()
# Draw font name in lilac-blue
draw.text((margin, y), f"{name}:", font=name_font, fill="#7289DA")
# Draw preview text with more horizontal space
draw.text((350, y), font_sample_text, font=preview_font, fill="#FFFFFF")
# Optional divider line for clarity
draw.line([(margin, y + spacing - 15), (img_width - margin, y + spacing - 15)], fill="#2f3136", width=2)
y += spacing
buffer = io.BytesIO()
img.save(buffer, format="PNG")
buffer.seek(0)
return buffer
return await asyncio.to_thread(_generate)
buffer = await generate_font_preview()
await interaction.followup.send(
content="Here are all available fonts:",
file=discord.File(buffer, "font_preview.png")
)
@app_commands.command(name="setprofile", description="Set your profile information.")
@app_commands.describe(
@@ -45,16 +104,7 @@ class Profiles(commands.Cog):
birthday="Your birthday (MM-DD)",
font_name="Font to use (see /listfonts)"
)
async def setprofile(self, interaction: discord.Interaction,
pronouns: str = None,
about_me: str = None,
fav_color: str = None,
bg_color: str = None,
fav_game: str = None,
fav_artist: str = None,
birthday: str = None,
font_name: str = None):
async def setprofile(self, interaction: discord.Interaction, pronouns: str = None, about_me: str = None, fav_color: str = None, bg_color: str = None, fav_game: str = None, fav_artist: str = None, birthday: str = None, font_name: str = None):
# Defer the response to show "thinking"
await interaction.response.defer(thinking=True)
@@ -76,7 +126,7 @@ class Profiles(commands.Cog):
db = get_db()
cursor = db.cursor()
# Build update query dynamically to only update provided fields
update_fields = []
values = []
@@ -126,10 +176,10 @@ class Profiles(commands.Cog):
placeholders = ["?"] * len(fields)
query = f"INSERT INTO profiles ({', '.join(fields)}) VALUES ({', '.join(placeholders)})"
cursor.execute(query, [interaction.user.id] + values)
db.commit()
db.close()
await interaction.followup.send("Your profile has been saved!")
@app_commands.command(name="profile", description="View your or another user's profile.")
@@ -138,22 +188,22 @@ class Profiles(commands.Cog):
await interaction.response.defer(thinking=True)
member = member or interaction.user
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT * FROM profiles WHERE user_id=?", (member.id,))
row = cursor.fetchone()
db.close()
if not row:
await interaction.followup.send("This user hasn't set up a profile yet. Use /setprofile to add information to your profile")
return
_, pronouns, about_me, fav_color, bg_color, fav_game, fav_artist, birthday, font_name = row
avatar_asset = member.display_avatar.with_size(256)
avatar_bytes = await avatar_asset.read()
def generate_image():
try:
if font_name:
@@ -181,7 +231,7 @@ class Profiles(commands.Cog):
font = ImageFont.load_default()
font_bold = ImageFont.load_default()
font_label = ImageFont.load_default()
img_width, img_height = 1000, 550
# Parse background color - only accept hex with #
@@ -205,7 +255,7 @@ class Profiles(commands.Cog):
radius=20,
fill=(40, 45, 52, 200)
)
# Avatar setup - centered in left panel
avatar_size = 200
panel_center = panel_left_x + panel_left_width // 2
@@ -215,23 +265,21 @@ class Profiles(commands.Cog):
# Draw glowing border around avatar
for offset in range(3):
draw.rounded_rectangle(
[(avatar_x - 6 - offset, avatar_y - 6 - offset),
[(avatar_x - 6 - offset, avatar_y - 6 - offset),
(avatar_x + avatar_size + 6 + offset, avatar_y + avatar_size + 6 + offset)],
radius=15,
outline=(88, 101, 242, 100 - offset * 30),
width=2
)
# Paste avatar with rounded corners
avatar = Image.open(io.BytesIO(avatar_bytes)).convert("RGBA")
avatar = avatar.resize((avatar_size, avatar_size))
mask = Image.new('L', (avatar_size, avatar_size), 0)
mask_draw = ImageDraw.Draw(mask)
mask_draw.rounded_rectangle([(0, 0), (avatar_size, avatar_size)], radius=12, fill=255)
img.paste(avatar, (avatar_x, avatar_y), mask)
# Draw username with shadow effect - centered in panel with dynamic sizing
username_y = avatar_y + avatar_size + 25
@@ -267,34 +315,52 @@ class Profiles(commands.Cog):
if text_width <= max_username_width:
break
username_font_size -= 2
# Shadow
draw.text((panel_center + 2, username_y + 2), member.display_name,
fill=(0, 0, 0, 100), font=username_font, anchor="mt")
draw.text((panel_center + 2, username_y + 2), member.display_name, fill=(0, 0, 0, 100), font=username_font, anchor="mt")
# Main text
draw.text((panel_center, username_y), member.display_name,
fill="#FFFFFF", font=username_font, anchor="mt")
draw.text((panel_center, username_y), member.display_name, fill="#FFFFFF", font=username_font, anchor="mt")
# Draw pronouns below username if available - centered in panel
# Draw pronouns below username if available - centered in panel with wrapping
current_y = username_y + 40
if pronouns:
draw.text((panel_center, current_y), pronouns,
fill="#B9BBBE", font=font, anchor="mt")
current_y += 35
# Wrap pronouns text to fit panel width
max_pronouns_width = panel_left_width - 20 # Leave some padding
words = pronouns.split()
line = ""
for word in words:
test_line = f"{line} {word}".strip()
bbox = draw.textbbox((0, 0), test_line, font=font)
line_width = bbox[2] - bbox[0]
if line_width <= max_pronouns_width:
line = test_line
else:
if line:
draw.text((panel_center, current_y), line, fill="#B9BBBE", font=font, anchor="mt")
current_y += 25 # Move to next line
line = word
# Draw any remaining text
if line:
draw.text((panel_center, current_y), line, fill="#B9BBBE", font=font, anchor="mt")
current_y += 35 # Space before roles
# Draw roles below pronouns
roles = [role for role in member.roles if role.name != "@everyone"]
if roles:
# Sort roles by position (highest first, like Discord does)
roles.sort(key=lambda r: r.position, reverse=True)
# Limit to top 5 roles to avoid overflow
display_roles = roles[:5]
role_y = current_y
role_font_size = 14
try:
if font_name:
font_path_ttf = os.path.join(FONTS_PATH, f"{font_name}.ttf")
@@ -317,10 +383,9 @@ class Profiles(commands.Cog):
# Draw role name centered
role_text = f"{role.name}"
draw.text((panel_center, role_y), role_text,
fill=role_color, font=role_font, anchor="mt")
draw.text((panel_center, role_y), role_text, fill=role_color, font=role_font, anchor="mt")
role_y += 22
# Right side panel
panel_x = 360
panel_y = 50
@@ -332,10 +397,10 @@ class Profiles(commands.Cog):
radius=20,
fill=(40, 45, 52, 150)
)
line_spacing = 50
max_text_width = panel_width - 60
fields = [
("Favorite Color", fav_color),
("Favorite Game", fav_game),
@@ -343,7 +408,7 @@ class Profiles(commands.Cog):
("Birthday", birthday),
("About Me", about_me)
]
for label, value in fields:
if value:
if label == "About Me":
@@ -359,10 +424,12 @@ class Profiles(commands.Cog):
words = value.split()
line = ""
first_line = True
for word in words:
test_line = f"{line} {word}".strip()
bbox = draw.textbbox((0, 0), test_line, font=font)
line_width = bbox[2] - bbox[0]
available_width = max_text_width - (label_width if first_line else 0)
if line_width <= available_width:
@@ -374,9 +441,11 @@ class Profiles(commands.Cog):
first_line = False
value_x = panel_x
line = word
if line:
draw.text((value_x if first_line else panel_x, panel_y), line, fill="#FFFFFF", font=font)
panel_y += line_spacing
panel_y += line_spacing
else:
# Draw label and value on same line
draw.text((panel_x, panel_y), f"{label}: ", fill="#7289DA", font=font_label)
@@ -387,13 +456,14 @@ class Profiles(commands.Cog):
# Draw value right after label
draw.text((panel_x + label_width, panel_y), str(value), fill="#FFFFFF", font=font)
panel_y += line_spacing
buffer = io.BytesIO()
img.save(buffer, format="PNG")
buffer.seek(0)
return buffer
buffer = await asyncio.to_thread(generate_image)
await interaction.followup.send(file=discord.File(buffer, "profile.png"))