| """ |
| Enhanced Theme and styling utilities for the bot. |
| Provides neon colors, progress bars, and decorative text formatting with rich visual elements. |
| Version 2.0 - Improved dividers, colors, headers, and emojis |
| """ |
|
|
| import random |
| from typing import Literal |
| from urllib.parse import urlparse |
|
|
| import discord |
|
|
| from bot.emojis import ui |
|
|
| |
| |
| |
|
|
| |
| NEON_CYAN = discord.Color.from_rgb(0, 255, 255) |
| NEON_PINK = discord.Color.from_rgb(255, 0, 200) |
| NEON_PURPLE = discord.Color.from_rgb(145, 70, 255) |
| NEON_LIME = discord.Color.from_rgb(57, 255, 20) |
| NEON_ORANGE = discord.Color.from_rgb(255, 140, 0) |
| NEON_YELLOW = discord.Color.from_rgb(255, 255, 0) |
| NEON_RED = discord.Color.from_rgb(255, 50, 50) |
| NEON_BLUE = discord.Color.from_rgb(50, 150, 255) |
| NEON_MAGENTA = discord.Color.from_rgb(255, 0, 255) |
| NEON_TEAL = discord.Color.from_rgb(0, 255, 200) |
|
|
| |
| NEON_GOLD = discord.Color.from_rgb(255, 215, 0) |
| NEON_SILVER = discord.Color.from_rgb(192, 192, 255) |
| NEON_ROSE = discord.Color.from_rgb(255, 102, 178) |
| NEON_SKY = discord.Color.from_rgb(135, 206, 250) |
| NEON_CORAL = discord.Color.from_rgb(255, 127, 80) |
| NEON_VIOLET = discord.Color.from_rgb(138, 43, 226) |
| NEON_MINT = discord.Color.from_rgb(152, 255, 152) |
| NEON_PEACH = discord.Color.from_rgb(255, 218, 185) |
| NEON_LAVENDER = discord.Color.from_rgb(230, 190, 255) |
| NEON_AQUA = discord.Color.from_rgb(0, 255, 255) |
| NEON_CRIMSON = discord.Color.from_rgb(220, 20, 60) |
| NEON_EMERALD = discord.Color.from_rgb(80, 200, 120) |
| NEON_AMBER = discord.Color.from_rgb(255, 191, 0) |
| NEON_INDIGO = discord.Color.from_rgb(75, 0, 130) |
|
|
| |
| NEON_PALETTE = [NEON_CYAN, NEON_PINK, NEON_PURPLE, NEON_LIME, NEON_ORANGE, NEON_YELLOW] |
| NEON_PASTEL_PALETTE = [NEON_LAVENDER, NEON_PEACH, NEON_MINT, NEON_SKY, NEON_ROSE] |
| NEON_DARK_PALETTE = [NEON_INDIGO, NEON_VIOLET, NEON_CRIMSON, NEON_MAGENTA] |
|
|
| |
| GLOW_EMOJIS = ["โจ", "โก", "๐", "๐", "๐ซ", "โ
", "โ
", "โฆ", "๐ ", "๐ฎ"] |
| SPARKLE_EMOJIS = ["โจ", "โ๏ธ", "โด๏ธ", "โ๏ธ", "๐ ", "โ
", "โ
"] |
| FIRE_EMOJIS = ["๐ฅ", "๐ฅ", "โก", "โ๏ธ", "โ
", "๐งก", "๐"] |
| HEART_EMOJIS = ["โ
", "<:animatedarrowgreen:1477261279428087979>", "๐", "<:animatedarrowgreen:1477261279428087979>", "๐", "๐งก", "<:animatedarrowpink:1477261266690113651>", "๐"] |
|
|
| |
| ARROW_BLUE = "๐ท" |
| ARROW_GREEN = "<:animatedarrowgreen:1477261279428087979>" |
| ARROW_PINK = "<:animatedarrowpink:1477261266690113651>" |
| ARROW_PURPLE = "<:animatedarrowgreen:1477261279428087979>" |
| ARROW_ORANGE = "๐ " |
| ARROW_YELLOW = "<:animatedarrowyellow:1477261257592668271>" |
| ARROW_CYAN = "๐ " |
| ARROW_RED = "๐ด" |
| ARROW_WHITE = "โช" |
| ARROW_BLACK = "โซ" |
|
|
|
|
| def pick_neon_color(seed: int | None = None) -> discord.Color: |
| """Pick a neon color, optionally based on a seed for consistency.""" |
| if seed is None: |
| return random.choice(NEON_PALETTE) |
| return NEON_PALETTE[seed % len(NEON_PALETTE)] |
|
|
|
|
| def pick_pastel_color(seed: int | None = None) -> discord.Color: |
| """Pick a pastel neon color.""" |
| if seed is None: |
| return random.choice(NEON_PASTEL_PALETTE) |
| return NEON_PASTEL_PALETTE[seed % len(NEON_PASTEL_PALETTE)] |
|
|
|
|
| def pick_dark_color(seed: int | None = None) -> discord.Color: |
| """Pick a dark neon color.""" |
| if seed is None: |
| return random.choice(NEON_DARK_PALETTE) |
| return NEON_DARK_PALETTE[seed % len(NEON_DARK_PALETTE)] |
|
|
|
|
| def pick_accent_color() -> discord.Color: |
| """Pick a random accent color.""" |
| accents = [NEON_CYAN, NEON_PINK, NEON_PURPLE, NEON_LIME, NEON_GOLD, NEON_ROSE] |
| return random.choice(accents) |
|
|
|
|
| def random_neon() -> discord.Color: |
| """Get a completely random neon color from all palettes.""" |
| all_colors = NEON_PALETTE + NEON_PASTEL_PALETTE + NEON_DARK_PALETTE |
| return random.choice(all_colors) |
|
|
|
|
| |
| |
| |
|
|
| def progress_bar( |
| current: int, |
| total: int, |
| *, |
| size: int = 12, |
| filled_char: str = "โ ", |
| empty_char: str = "โก", |
| show_percentage: bool = True |
| ) -> str: |
| """Create a customizable text-based progress bar.""" |
| total = max(1, total) |
| ratio = max(0.0, min(1.0, current / total)) |
| filled = round(ratio * size) |
| bar = f"{filled_char * filled}{empty_char * (size - filled)}" |
| if show_percentage: |
| return f"{bar} **{int(ratio * 100)}%**" |
| return bar |
|
|
|
|
| def xp_progress_bar(current: int, total: int, level: int) -> str: |
| """Create an XP progress bar with level display.""" |
| total = max(1, total) |
| ratio = max(0.0, min(1.0, current / total)) |
| filled = round(ratio * 10) |
| bar = f"{'โ' * filled}{'โ' * (10 - filled)}" |
| return f"Level **{level}** โข `{bar}` **{int(ratio * 100)}%**" |
|
|
|
|
| def health_bar(current: int, total: int, size: int = 10) -> str: |
| """Create a health/HP style progress bar.""" |
| total = max(1, total) |
| ratio = max(0.0, min(1.0, current / total)) |
| filled = round(ratio * size) |
| |
| if ratio > 0.7: |
| color = "๐ฉ" |
| elif ratio > 0.4: |
| color = "๐จ" |
| else: |
| color = "๐ฅ" |
| |
| bar = f"{color * filled}{'โฌ' * (size - filled)}" |
| return f"{bar} `{current}/{total}`" |
|
|
|
|
| def cooldown_bar(remaining: int, total: int) -> str: |
| """Create a cooldown timer bar.""" |
| total = max(1, total) |
| elapsed = max(0, total - remaining) |
| ratio = elapsed / total |
| filled = round(ratio * 8) |
| bar = f"{'โณ' * filled}{'โ' * (8 - filled)}" |
| return f"{bar} **{remaining}s** remaining" |
|
|
|
|
| def fancy_progress_bar(current: int, total: int, style: str = "default") -> str: |
| """Create a fancy styled progress bar.""" |
| total = max(1, total) |
| ratio = max(0.0, min(1.0, current / total)) |
| filled = round(ratio * 10) |
| |
| styles = { |
| "default": ("โ", "โ"), |
| "blocks": ("โ", "โ"), |
| "circles": ("โ", "โ"), |
| "diamonds": ("โ", "โ"), |
| "stars": ("โ
", "โ"), |
| "hearts": ("โ
", "๐ค"), |
| "fire": ("๐ฅ", "๐จ"), |
| "arrows": ("โถ", "โท"), |
| } |
| |
| filled_char, empty_char = styles.get(style, styles["default"]) |
| bar = f"{filled_char * filled}{empty_char * (10 - filled)}" |
| return f"`{bar}` **{int(ratio * 100)}%**" |
|
|
|
|
| |
| |
| |
|
|
| def shimmer(text: str) -> str: |
| """Add shimmer effects around text.""" |
| return f"{random.choice(GLOW_EMOJIS)} {text} {random.choice(GLOW_EMOJIS)}" |
|
|
|
|
| def fancy_header(text: str, style: str = "default") -> str: |
| """Create a fancy header with decorative brackets - 20 styles available.""" |
| styles = { |
| "default": f"ใ {text} ใ", |
| "double": f"ใ {text} ใ", |
| "stars": f"โ
{text} โ
", |
| "sparkle": f"โจ {text} โจ", |
| "fire": f"๐ฅ {text} ๐ฅ", |
| "diamond": f"โ {text} โ", |
| "arrow": f"โค {text} โค", |
| "crown": f"๐ {text} ๐", |
| "glow": f"โโ {text} โโ", |
| "cyber": f"ใ {text} ใ", |
| "neon": f"โโโ {text} โโโ", |
| |
| "bullet": f"โข โข โข {text} โข โข โข", |
| "wave": f"๏ฝ๏ฝ๏ฝ {text} ๏ฝ๏ฝ๏ฝ", |
| "box": f"โโโ {text} โโโ", |
| "hex": f"โฌก {text} โฌก", |
| "infinity": f"โ {text} โ", |
| "lightning": f"โก {text} โก", |
| "heart": f"๐ {text} ๐", |
| "moon": f"๐ {text} ๐", |
| "sun": f"โ๏ธ {text} โ๏ธ", |
| "flower": f"๐ธ {text} ๐ธ", |
| "gem": f"๐ {text} ๐", |
| "music": f"๐ต {text} ๐ต", |
| "game": f"๐ฎ {text} ๐ฎ", |
| "rocket": f"๐ {text} ๐", |
| "shield": f"๐ก๏ธ {text} ๐ก๏ธ", |
| "trophy": f"๐ {text} ๐", |
| "party": f"๐ {text} ๐", |
| "cloud": f"โ๏ธ {text} โ๏ธ", |
| "star2": f"โ
{text} โ
", |
| } |
| return styles.get(style, styles["default"]) |
|
|
|
|
| def mega_title(text: str, style: str = "default") -> str: |
| """Create an eye-catching mega title - multiple styles.""" |
| styles = { |
| "default": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n **{text}**\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| "double": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n **{text}**\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| "stars": f"โ
โโโโโโโโโโโโโโโโโโโโโโโโโ โ\n **{text}**\nโโโโโโโโโโโโโโโโโโโโโโโโโ โ
", |
| "fire": f"๐ฅ โโโโโโโโโโโโโโโโโโโโโ ๐ฅ\n **{text}**\n๐ฅ โโโโโโโโโโโโโโโโโโโโโ ๐ฅ", |
| "simple": f"โโโโโโโโโโโโโโโโโโโโโโ\n **{text}**\nโโโโโโโโโโโโโโโโโโโโโโ", |
| "dots": f"โข โข โข โข โข โข โข โข โข โข โข โข\n **{text}**\nโข โข โข โข โข โข โข โข โข โข โข โข", |
| } |
| return styles.get(style, styles["default"]) |
|
|
|
|
| def panel_title(emoji: str, text: str, style: str = "default") -> str: |
| """Create a panel title with emoji decoration - 10 styles.""" |
| styles = { |
| "default": f"{emoji} **{text}**", |
| "fancy": f"โง {emoji} **{text}** โง", |
| "bold": f"โธ {emoji} **{text}** โ", |
| "sparkle": f"โจ {emoji} **{text}** โจ", |
| "fire": f"๐ฅ {emoji} **{text}** ๐ฅ", |
| "crown": f"๐ {emoji} **{text}** ๐", |
| "star": f"โ
{emoji} **{text}** โ
", |
| "diamond": f"๐ {emoji} **{text}** ๐", |
| "heart": f"๐ {emoji} **{text}** ๐", |
| "arrow": f"โค {emoji} **{text}**", |
| } |
| return styles.get(style, styles["default"]) |
|
|
|
|
| def animated_header(text: str) -> str: |
| """Create a header with animated-style decoration.""" |
| emojis = random.sample(GLOW_EMOJIS, 2) |
| return f"{emojis[0]} โโโโ **{text}** โโโโ {emojis[1]}" |
|
|
|
|
| def gradient_header(text: str) -> str: |
| """Create a gradient-style header.""" |
| return f"โโโโ **{text}** โโโโ" |
|
|
|
|
| |
| |
| |
|
|
| def section_bar(emoji: str = "โฌ", length: int = 24) -> str: |
| """Create a section divider bar.""" |
| return f"{emoji}" * length |
|
|
|
|
| def panel_divider(color: Literal["blue", "green", "pink", "purple", "orange", "yellow", "cyan", "lime", "red", "white", "gold", "rainbow"] = "blue", length: int = 8) -> str: |
| """Create a colored divider using emojis (two-line style for clarity). |
| |
| Colors: blue, green, pink, purple, orange, yellow, cyan, lime, red, white, gold, rainbow |
| Length: 4-12 emojis per line (default 8) |
| """ |
| arrows = { |
| "blue": ARROW_BLUE, |
| "green": ARROW_GREEN, |
| "pink": ARROW_PINK, |
| "purple": ARROW_PURPLE, |
| "orange": ARROW_ORANGE, |
| "yellow": ARROW_YELLOW, |
| "cyan": ARROW_CYAN, |
| "lime": "<:animatedarrowgreen:1477261279428087979>", |
| "red": ARROW_RED, |
| "white": ARROW_WHITE, |
| "gold": "<:animatedarrowyellow:1477261257592668271>", |
| "rainbow": None, |
| } |
| |
| length = max(4, min(12, length)) |
| |
| if color == "rainbow": |
| colors = ["๐ด", "๐ ", "<:animatedarrowyellow:1477261257592668271>", "<:animatedarrowgreen:1477261279428087979>", "๐ต", "๐ฃ"] |
| line1 = " ".join(colors[:length//2]) |
| line2 = " ".join(colors[length//2:length]) |
| return f"{line1}\n{line2}" |
| |
| arrow = arrows.get(color, ARROW_BLUE) |
| line = " ".join([arrow] * length) |
| |
| return f"{line}\n{line}" |
|
|
|
|
| def fancy_divider(style: Literal["stars", "dots", "lines", "diamonds", "hearts", "waves", "fire", "lightning", "flowers", "moons", "clouds", "music", "gaming"] = "stars", length: int = 20) -> str: |
| """Create a fancy two-line divider with various styles for better visibility.""" |
| length = max(10, min(30, length)) |
| half = length // 2 |
| |
| dividers = { |
| "stars": f"โ
{'โ' * half} โ
\nโ
{'โ' * half} โ
", |
| "dots": f"โข โข โข {'โ' * (half-3)} โข โข โข\nโข โข โข {'โ' * (half-3)} โข โข โข", |
| "lines": f"{'โ' * length}\n{'โ' * length}", |
| "diamonds": f"โ {'โ' * half} โ\nโ {'โ' * half} โ", |
| "hearts": f"๐ {'โ' * (half-2)} ๐\n๐ {'โ' * (half-2)} ๐", |
| "waves": f"{'ใ' * length}\n{'ใ' * length}", |
| "fire": f"๐ฅ {'โ' * half} ๐ฅ\n๐ฅ {'โ' * half} ๐ฅ", |
| "lightning": f"โก {'โ' * half} โก\nโก {'โ' * half} โก", |
| "flowers": f"๐ธ {'โ' * half} ๐ธ\n๐ธ {'โ' * half} ๐ธ", |
| "moons": f"๐ {'โ' * half} ๐\n๐ {'โ' * half} ๐", |
| "clouds": f"โ๏ธ {'โ' * half} โ๏ธ\nโ๏ธ {'โ' * half} โ๏ธ", |
| "music": f"๐ต {'โ' * half} ๐ต\n๐ต {'โ' * half} ๐ต", |
| "gaming": f"๐ฎ {'โ' * half} ๐ฎ\n๐ฎ {'โ' * half} ๐ฎ", |
| } |
| return dividers.get(style, dividers["stars"]) |
|
|
|
|
| def double_line(length: int = 40) -> str: |
| """Create a double line divider.""" |
| return "โ" * max(10, min(50, length)) |
|
|
|
|
| def triple_line(length: int = 40) -> str: |
| """Create a triple line divider with center decoration.""" |
| length = max(10, min(50, length)) |
| return f"{'โ' * (length//2)} โฆ {'โ' * (length//2)}" |
|
|
|
|
| def dotted_line(length: int = 30) -> str: |
| """Create a dotted line divider.""" |
| return "โข" * max(5, min(40, length)) |
|
|
|
|
| def gradient_line(length: int = 20) -> str: |
| """Create a gradient-style line.""" |
| return f"{'โ' * 5}{'โ' * 5}{'โ' * 5}{'โ' * 5}" |
|
|
|
|
| def arrow_line(direction: str = "right", length: int = 10) -> str: |
| """Create an arrow line divider.""" |
| if direction == "right": |
| return "โถ " + "โ" * length + " โถ" |
| elif direction == "left": |
| return "โ " + "โ" * length + " โ" |
| else: |
| return "โ " + "โ" * length + " โถ" |
|
|
|
|
| def box_divider(text: str = "", width: int = 30) -> str: |
| """Create a box-style divider with optional text.""" |
| if text: |
| return f"โ{'โ' * (width-2)}โ\nโ {text.center(width-4)} โ\nโ{'โ' * (width-2)}โ" |
| return f"โ{'โ' * (width-2)}โ\nโ {'โ' * (width-2)}โฃ\nโ{'โ' * (width-2)}โ" |
|
|
|
|
| |
| |
| |
|
|
| def section_header(emoji: str, text: str, color: str = "default") -> str: |
| """Create a section header with emoji and text.""" |
| colors = { |
| "default": "", |
| "cyan": "๐ฉต", |
| "pink": "<:animatedarrowpink:1477261266690113651>", |
| "purple": "<:animatedarrowgreen:1477261279428087979>", |
| "green": "<:animatedarrowgreen:1477261279428087979>", |
| "yellow": "๐", |
| "orange": "๐งก", |
| "red": "โ
", |
| "blue": "๐", |
| "gold": "๐ช", |
| "silver": "๐ชฉ", |
| } |
| accent = colors.get(color, "") |
| if accent: |
| return f"{accent} {emoji} **{text}** {accent}" |
| return f"{emoji} **{text}**" |
|
|
|
|
| def boxed_section(title: str, content: str, emoji: str = "๐") -> str: |
| """Create a boxed section with title and content.""" |
| return ( |
| f"โญโโโ {emoji} **{title}** โโโโฎ\n" |
| f"โ {content}\n" |
| f"โฐโโโโโโโโโโโโโโโฏ" |
| ) |
|
|
|
|
| def card(title: str, content: str, emoji: str = "๐ด", color: str = "blue") -> str: |
| """Create a card-style display.""" |
| divider = panel_divider(color) |
| return f"{divider}\n{emoji} **{title}**\n{content}\n{divider}" |
|
|
|
|
| def info_box(title: str, content: str, style: str = "info") -> str: |
| """Create an info box with style.""" |
| styles = { |
| "info": ("โน๏ธ", "๐ท"), |
| "success": ("โ
", "<:animatedarrowgreen:1477261279428087979>"), |
| "warning": ("โ ๏ธ", "๐ "), |
| "error": ("โ", "๐ด"), |
| "tip": ("๐ก", "<:animatedarrowyellow:1477261257592668271>"), |
| } |
| emoji, border = styles.get(style, styles["info"]) |
| return f"{border}{border}{border}{border}{border}\n{emoji} **{title}**\n{content}\n{border}{border}{border}{border}{border}" |
|
|
|
|
| |
| |
| |
|
|
| def coin_display(amount: int) -> str: |
| """Display coins with diamond emoji.""" |
| return f"๐ `{amount:,}`" |
|
|
|
|
| def xp_display(amount: int, level: int) -> str: |
| """Display XP and level with star emoji.""" |
| return f"โ
Level `{level}` โข XP `{amount:,}`" |
|
|
|
|
| def money_display(wallet: int, bank: int = 0) -> str: |
| """Display wallet and bank amounts beautifully.""" |
| result = f"๐ฐ **Wallet:** `{wallet:,}`" |
| if bank > 0: |
| result += f"\n๐ฆ **Bank:** `{bank:,}`" |
| return result |
|
|
|
|
| def rank_display(rank: int) -> str: |
| """Display rank with medal/badge.""" |
| badges = {1: "๐ฅ", 2: "๐ฅ", 3: "๐ฅ"} |
| badge = badges.get(rank, f"#{rank}") |
| return f"{badge} **Rank #{rank}**" |
|
|
|
|
| def level_display(level: int) -> str: |
| """Display level with decoration.""" |
| if level >= 100: |
| return f"๐ **Level {level}**" |
| elif level >= 50: |
| return f"โ
**Level {level}**" |
| elif level >= 25: |
| return f"โจ **Level {level}**" |
| return f"๐ฑ **Level {level}**" |
|
|
|
|
| def timestamp_display(seconds: int) -> str: |
| """Display duration in human-readable format.""" |
| if seconds < 60: |
| return f"โฑ๏ธ `{seconds}s`" |
| elif seconds < 3600: |
| mins = seconds // 60 |
| secs = seconds % 60 |
| return f"โฑ๏ธ `{mins}m {secs}s`" |
| else: |
| hours = seconds // 3600 |
| mins = (seconds % 3600) // 60 |
| return f"โฑ๏ธ `{hours}h {mins}m`" |
|
|
|
|
| def status_display(status: str) -> str: |
| """Display status with colored indicator.""" |
| statuses = { |
| "online": "<:animatedarrowgreen:1477261279428087979> Online", |
| "idle": "<:animatedarrowyellow:1477261257592668271> Idle", |
| "dnd": "๐ด Do Not Disturb", |
| "offline": "โซ Offline", |
| "playing": "๐ฎ Playing", |
| "listening": "๐ต Listening", |
| "watching": "๐ Watching", |
| "streaming": "๐บ Streaming", |
| } |
| return statuses.get(status.lower(), f"โ {status}") |
|
|
|
|
| def badge_display(badge_type: str) -> str: |
| """Display a badge by type.""" |
| badges = { |
| "owner": "๐ Owner", |
| "admin": "๐ก๏ธ Admin", |
| "mod": "โ๏ธ Moderator", |
| "vip": "๐ VIP", |
| "boost": "๐ Booster", |
| "verified": "โ
Verified", |
| "bot": "๐ค Bot", |
| "developer": "๐ป Developer", |
| "premium": "โ
Premium", |
| "founder": "๐
Founder", |
| } |
| return badges.get(badge_type.lower(), f"๐ {badge_type}") |
|
|
|
|
| |
| |
| |
|
|
| def music_now_playing(title: str, requester: str, duration: str = "") -> str: |
| """Format a 'now playing' message for music.""" |
| result = f"๐ต **Now Playing**\n{panel_divider('cyan')}\n๐ถ **{title}**" |
| if duration: |
| result += f"\nโฑ๏ธ Duration: `{duration}`" |
| result += f"\n๐ค Requested by: {requester}" |
| return result |
|
|
|
|
| def music_queue_item(position: int, title: str, requester: str) -> str: |
| """Format a queue item display.""" |
| return f"`{position}.` ๐ต **{title[:40]}{'...' if len(title) > 40 else ''}** โข {requester}" |
|
|
|
|
| def music_controls_display() -> str: |
| """Display music control instructions.""" |
| return ( |
| f"{panel_divider('green')}\n" |
| f"โฎ๏ธ **Previous** | โถ๏ธ **Play** | โธ๏ธ **Pause** | โญ๏ธ **Skip** | โน๏ธ **Stop**\n" |
| f"{panel_divider('green')}" |
| ) |
|
|
|
|
| def music_status(playing: bool, paused: bool = False, queue_count: int = 0) -> str: |
| """Display music status indicator.""" |
| if paused: |
| return "โธ๏ธ **Paused**" |
| elif playing: |
| return f"โถ๏ธ **Playing** โข {queue_count} in queue" |
| else: |
| return "โน๏ธ **Not Playing**" |
|
|
|
|
| |
| |
| |
|
|
| def economy_wallet_display(wallet: int, bank: int) -> str: |
| """Format wallet and bank display for economy panel.""" |
| return ( |
| f"๐ **Wallet:** `{wallet:,}` ๐ฐ\n" |
| f"๐ฆ **Bank:** `{bank:,}` ๐" |
| ) |
|
|
|
|
| def economy_transaction(amount: int, action: str) -> str: |
| """Format an economy transaction display.""" |
| actions = { |
| "daily": ("๐
Daily Reward", NEON_LIME), |
| "work": ("๐ผ Work Payment", NEON_CYAN), |
| "gamble_win": ("๐ฐ Gamble Win!", NEON_LIME), |
| "gamble_loss": ("๐ฐ Gamble Loss", NEON_RED), |
| "rob_success": ("๐ฆ Robbery Success!", NEON_LIME), |
| "rob_fail": ("๐จ Robbery Failed!", NEON_RED), |
| "deposit": ("๐ฅ Deposit", NEON_BLUE), |
| "withdraw": ("๐ค Withdraw", NEON_PURPLE), |
| "shop_buy": ("๐ Purchase", NEON_ORANGE), |
| "shop_sell": ("๐ฐ Sale", NEON_YELLOW), |
| "gift_sent": ("๐ Gift Sent", NEON_PINK), |
| "gift_received": ("๐ Gift Received", NEON_LIME), |
| } |
| label, _ = actions.get(action, ("๐ฐ Transaction", NEON_CYAN)) |
| return f"{label}: `{amount:,}`" |
|
|
|
|
| def economy_leaderboard(position: int, name: str, balance: int) -> str: |
| """Format economy leaderboard entry.""" |
| badges = {1: "๐ฅ", 2: "๐ฅ", 3: "๐ฅ"} |
| badge = badges.get(position, f"#{position}") |
| return f"{badge} **{name}** โ ๐ฐ `{balance:,}`" |
|
|
|
|
| |
| |
| |
|
|
| def success_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a success embed with green color and decorations.""" |
| embed = discord.Embed( |
| title=f"โ
{title}", |
| description=f"{panel_divider('green')}\n{description}" if description else panel_divider('green'), |
| color=NEON_LIME, |
| ) |
| return embed |
|
|
|
|
| def error_embed(title: str, description: str = "") -> discord.Embed: |
| """Create an error embed with red/pink color.""" |
| embed = discord.Embed( |
| title=f"โ {title}", |
| description=f"{panel_divider('red')}\n{description}" if description else panel_divider('red'), |
| color=NEON_RED, |
| ) |
| return embed |
|
|
|
|
| def warning_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a warning embed with orange color.""" |
| embed = discord.Embed( |
| title=f"โ ๏ธ {title}", |
| description=f"{panel_divider('orange')}\n{description}" if description else panel_divider('orange'), |
| color=NEON_ORANGE, |
| ) |
| return embed |
|
|
|
|
| def info_embed(title: str, description: str = "") -> discord.Embed: |
| """Create an info embed with cyan color.""" |
| embed = discord.Embed( |
| title=f"โน๏ธ {title}", |
| description=f"{panel_divider('blue')}\n{description}" if description else panel_divider('blue'), |
| color=NEON_CYAN, |
| ) |
| return embed |
|
|
|
|
| def idle_text(summary: str, details: str = "") -> str: |
| """Format a compact idle-state text block for panels/commands.""" |
| body = f"{status_display('idle')} {summary}" |
| if details: |
| return f"{body}\n{panel_divider('orange')}\n{details}" |
| return body |
|
|
|
|
| def idle_embed(title: str = "Idle State", details: str = "", hint: str = "") -> discord.Embed: |
| """Create a standardized idle-state embed used across commands/panels.""" |
| content = details or "No active items yet." |
| embed = discord.Embed( |
| title=f"{status_display('idle')} ใ {title} ใ", |
| description=( |
| f"{panel_divider('orange')}\n" |
| f"โข {content}\n" |
| f"{panel_divider('orange')}" |
| ), |
| color=NEON_ORANGE, |
| ) |
| if hint: |
| embed.set_footer(text=hint) |
| return embed |
|
|
|
|
| async def idle_embed_for_guild( |
| title: str = "Idle State", |
| details: str = "", |
| hint: str = "", |
| *, |
| guild: discord.Guild | None = None, |
| bot = None, |
| ) -> discord.Embed: |
| """Create idle embed and attach guild banner/icon when available.""" |
| embed = idle_embed(title, details, hint) |
| if guild is not None: |
| await add_banner_to_embed(embed, guild, bot) |
| return embed |
|
|
|
|
| def loading_embed(title: str = "Loading...", description: str = "") -> discord.Embed: |
| """Create a loading embed with animation indication.""" |
| embed = discord.Embed( |
| title=f"โณ {title}", |
| description=description or "Please wait...", |
| color=NEON_PURPLE, |
| ) |
| return embed |
|
|
|
|
| def gaming_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a gaming-themed embed.""" |
| embed = discord.Embed( |
| title=f"๐ฎ {title}", |
| description=f"{fancy_divider('gaming')}\n{description}" if description else fancy_divider('gaming'), |
| color=NEON_PURPLE, |
| ) |
| return embed |
|
|
|
|
| def economy_embed(title: str, description: str = "") -> discord.Embed: |
| """Create an economy-themed embed.""" |
| embed = discord.Embed( |
| title=f"๐ฐ {title}", |
| description=f"{panel_divider('gold')}\n{description}" if description else panel_divider('gold'), |
| color=NEON_GOLD, |
| ) |
| return embed |
|
|
|
|
| def music_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a music-themed embed.""" |
| embed = discord.Embed( |
| title=f"๐ต {title}", |
| description=f"{fancy_divider('music')}\n{description}" if description else fancy_divider('music'), |
| color=NEON_CYAN, |
| ) |
| return embed |
|
|
|
|
| def leaderboard_embed(title: str = "Leaderboard", description: str = "") -> discord.Embed: |
| """Create a leaderboard embed with trophy theme.""" |
| embed = discord.Embed( |
| title=f"๐ {title}", |
| description=f"{panel_divider('yellow')}\n{description}" if description else panel_divider('yellow'), |
| color=NEON_YELLOW, |
| ) |
| return embed |
|
|
|
|
| def profile_embed(username: str, avatar_url: str | None = None) -> discord.Embed: |
| """Create a profile embed base.""" |
| embed = discord.Embed( |
| title=f"๐ค {username}'s Profile", |
| description=panel_divider('purple'), |
| color=NEON_PURPLE, |
| ) |
| if avatar_url: |
| embed.set_thumbnail(url=avatar_url) |
| return embed |
|
|
|
|
| def tournament_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a tournament embed.""" |
| embed = discord.Embed( |
| title=f"๐ {title}", |
| description=f"{panel_divider('lime')}\n{description}" if description else panel_divider('lime'), |
| color=NEON_LIME, |
| ) |
| return embed |
|
|
|
|
| def shop_embed(title: str = "Shop", description: str = "") -> discord.Embed: |
| """Create a shop embed.""" |
| embed = discord.Embed( |
| title=f"๐ {title}", |
| description=f"{panel_divider('gold')}\n{description}" if description else panel_divider('gold'), |
| color=NEON_GOLD, |
| ) |
| return embed |
|
|
|
|
| def ticket_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a ticket/support embed.""" |
| embed = discord.Embed( |
| title=f"๐ซ {title}", |
| description=f"{panel_divider('cyan')}\n{description}" if description else panel_divider('cyan'), |
| color=NEON_CYAN, |
| ) |
| return embed |
|
|
|
|
| def giveaway_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a giveaway embed.""" |
| embed = discord.Embed( |
| title=f"๐ {title}", |
| description=f"{fancy_divider('stars')}\n{description}" if description else fancy_divider('stars'), |
| color=NEON_PINK, |
| ) |
| return embed |
|
|
|
|
| def poll_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a poll embed.""" |
| embed = discord.Embed( |
| title=f"๐ {title}", |
| description=f"{panel_divider('blue')}\n{description}" if description else panel_divider('blue'), |
| color=NEON_BLUE, |
| ) |
| return embed |
|
|
|
|
| def moderation_embed(title: str, description: str = "") -> discord.Embed: |
| """Create a moderation embed.""" |
| embed = discord.Embed( |
| title=f"๐ก๏ธ {title}", |
| description=f"{panel_divider('red')}\n{description}" if description else panel_divider('red'), |
| color=NEON_RED, |
| ) |
| return embed |
|
|
|
|
| def welcome_embed(username: str, server_name: str) -> discord.Embed: |
| """Create a welcome embed.""" |
| embed = discord.Embed( |
| title=f"๐ Welcome to {server_name}!", |
| description=f"{fancy_divider('hearts')}\nHey **{username}**, welcome to our server! ๐\nWe're glad to have you here!", |
| color=NEON_LIME, |
| ) |
| return embed |
|
|
|
|
| def goodbye_embed(username: str, server_name: str) -> discord.Embed: |
| """Create a goodbye embed.""" |
| embed = discord.Embed( |
| title=f"๐ Goodbye!", |
| description=f"{fancy_divider('waves')}\n**{username}** has left {server_name}.\nWe hope to see you again! <:animatedarrowgreen:1477261279428087979>", |
| color=NEON_ORANGE, |
| ) |
| return embed |
|
|
|
|
| |
| |
| |
|
|
| def format_leaderboard(entries: list[tuple[int, str, int]], emoji: str = "๐") -> str: |
| """Format a leaderboard from entries (rank, name, score).""" |
| lines = [] |
| for rank, name, score in entries: |
| badge = {1: "๐ฅ", 2: "๐ฅ", 3: "๐ฅ"}.get(rank, f"#{rank}") |
| lines.append(f"{badge} **{name}** โ `{score:,}`") |
| return "\n".join(lines) |
|
|
|
|
| def format_list(items: list[str], style: str = "bullet") -> str: |
| """Format a list of items with various styles.""" |
| styles = { |
| "bullet": "โข", |
| "arrow": "โ", |
| "star": "โ
", |
| "diamond": "โ", |
| "check": "โ", |
| "number": "{i}.", |
| "heart": "๐", |
| "fire": "๐ฅ", |
| "music": "๐ต", |
| } |
| |
| prefix = styles.get(style, "โข") |
| lines = [] |
| for i, item in enumerate(items, 1): |
| if "{i}" in prefix: |
| lines.append(f"{prefix.format(i=i)} {item}") |
| else: |
| lines.append(f"{prefix} {item}") |
| return "\n".join(lines) |
|
|
|
|
| def format_queue(tracks: list[str], max_display: int = 10) -> str: |
| """Format a music queue display.""" |
| if not tracks: |
| return "Queue is empty" |
| |
| lines = [] |
| for i, track in enumerate(tracks[:max_display], 1): |
| lines.append(f"`{i}.` ๐ต {track[:45]}{'...' if len(track) > 45 else ''}") |
| |
| if len(tracks) > max_display: |
| remaining = len(tracks) - max_display |
| lines.append(f"\n*...and {remaining} more tracks*") |
| |
| return "\n".join(lines) |
|
|
|
|
| def format_permissions(permissions: list[str]) -> str: |
| """Format a list of permissions nicely.""" |
| return " โข ".join(f"โ
{p}" for p in permissions) |
|
|
|
|
| def format_settings(settings: dict[str, str | bool | int]) -> str: |
| """Format settings dictionary nicely.""" |
| lines = [] |
| for key, value in settings.items(): |
| if isinstance(value, bool): |
| status = "โ
" if value else "โ" |
| lines.append(f"{status} **{key}**") |
| else: |
| lines.append(f"โ๏ธ **{key}:** `{value}`") |
| return "\n".join(lines) |
|
|
|
|
| |
| |
| |
|
|
| def create_field(name: str, value: str, inline: bool = False) -> dict: |
| """Create a field dict for embed.add_field().""" |
| return {"name": name, "value": value, "inline": inline} |
|
|
|
|
| def format_number(num: int) -> str: |
| """Format a number with commas and appropriate suffix.""" |
| if num >= 1_000_000_000: |
| return f"{num/1_000_000_000:.1f}B" |
| elif num >= 1_000_000: |
| return f"{num/1_000_000:.1f}M" |
| elif num >= 1_000: |
| return f"{num/1_000:.1f}K" |
| return f"{num:,}" |
|
|
|
|
| def truncate(text: str, length: int = 50, suffix: str = "...") -> str: |
| """Truncate text to a specific length.""" |
| if len(text) <= length: |
| return text |
| return text[:length-len(suffix)] + suffix |
|
|
|
|
| def highlight(text: str, style: str = "bold") -> str: |
| """Highlight text with markdown.""" |
| styles = { |
| "bold": f"**{text}**", |
| "italic": f"*{text}*", |
| "underline": f"__{text}__", |
| "strike": f"~~{text}~~", |
| "code": f"`{text}`", |
| "codeblock": f"```\n{text}\n```", |
| "quote": f"> {text}", |
| "spoiler": f"||{text}||", |
| } |
| return styles.get(style, text) |
|
|
|
|
| def code_block(code: str, language: str = "") -> str: |
| """Create a code block.""" |
| return f"```{language}\n{code}\n```" |
|
|
|
|
| def quote(text: str) -> str: |
| """Create a quote.""" |
| lines = text.split("\n") |
| return "\n".join(f"> {line}" for line in lines) |
|
|
|
|
| def spoiler(text: str) -> str: |
| """Create spoiler text.""" |
| return f"||{text}||" |
|
|
|
|
| def mention_user(user_id: int) -> str: |
| """Create a user mention.""" |
| return f"<@{user_id}>" |
|
|
|
|
| def mention_role(role_id: int) -> str: |
| """Create a role mention.""" |
| return f"<@&{role_id}>" |
|
|
|
|
| def mention_channel(channel_id: int) -> str: |
| """Create a channel mention.""" |
| return f"<#{channel_id}>" |
|
|
|
|
| def timestamp(time: int, style: str = "R") -> str: |
| """Create a Discord timestamp.""" |
| styles = { |
| "short": "t", |
| "long": "T", |
| "short_date": "d", |
| "long_date": "D", |
| "short_full": "f", |
| "long_full": "F", |
| "relative": "R", |
| } |
| return f"<t:{time}:{styles.get(style, 'R')}>" |
|
|
|
|
| |
| |
| |
|
|
| |
| BORDER_STYLES = { |
| "single": ("โ", "โ", "โ", "โ", "โ", "โ"), |
| "double": ("โ", "โ", "โ", "โ", "โ", "โ"), |
| "rounded": ("โญ", "โ", "โฎ", "โ", "โฐ", "โฏ"), |
| "bold": ("โ", "โ", "โ", "โ", "โ", "โ"), |
| "stars": ("โ
", "โ", "โ
", "โ", "โ
", "โ
"), |
| "diamonds": ("โ", "โ", "โ", "โ", "โ", "โ"), |
| "hearts": ("๐", "โ", "๐", "โ", "๐", "๐"), |
| "fire": ("๐ฅ", "โ", "๐ฅ", "โ", "๐ฅ", "๐ฅ"), |
| "lightning": ("โก", "โ", "โก", "โ", "โก", "โก"), |
| "sparkle": ("โจ", "โ", "โจ", "โ", "โจ", "โจ"), |
| } |
|
|
| |
| BULLET_STYLES = { |
| "star": "โ
", |
| "diamond": "โ", |
| "arrow": "โค", |
| "check": "โ", |
| "cross": "โ", |
| "heart": "โ
", |
| "sparkle": "โฆ", |
| "fire": "๐ฅ", |
| "music": "๐ต", |
| "gaming": "๐ฎ", |
| "trophy": "๐", |
| "crown": "๐", |
| "gem": "๐", |
| "rocket": "๐", |
| "lightning": "โก", |
| "flower": "๐ธ", |
| "moon": "๐", |
| "sun": "โ๏ธ", |
| "cloud": "โ๏ธ", |
| "rainbow": "๐", |
| } |
|
|
|
|
| def beautiful_border(text: str, style: str = "double", padding: int = 2) -> str: |
| """Create a beautiful bordered text box. |
| |
| Styles: single, double, rounded, bold, stars, diamonds, hearts, fire, lightning, sparkle |
| """ |
| tl, h, tr, v, bl, br = BORDER_STYLES.get(style, BORDER_STYLES["double"]) |
| lines = text.split("\n") |
| max_len = max(len(line) for line in lines) |
| width = max_len + padding * 2 |
| |
| result = [] |
| result.append(f"{tl}{h * width}{tr}") |
| for line in lines: |
| result.append(f"{v}{' ' * padding}{line.ljust(max_len)}{' ' * padding}{v}") |
| result.append(f"{bl}{h * width}{br}") |
| |
| return "\n".join(result) |
|
|
|
|
| def command_card(command_name: str, description: str, emoji: str = "โจ", category: str = "") -> str: |
| """Create a beautiful command card display.""" |
| border = "โญ" + "โ" * 40 + "โฎ" |
| border_end = "โฐ" + "โ" * 40 + "โฏ" |
| |
| lines = [ |
| border, |
| f"โ {emoji} **/{command_name}**", |
| ] |
| |
| if category: |
| lines.append(f"โ ๐ Category: {category}") |
| |
| lines.append(f"โ ๐ฌ {description[:50]}{'...' if len(description) > 50 else ''}") |
| lines.append(border_end) |
| |
| return "\n".join(lines) |
|
|
|
|
| def beautiful_list(items: list[str], style: str = "sparkle", numbered: bool = False) -> str: |
| """Create a beautifully formatted list. |
| |
| Styles: star, diamond, arrow, check, heart, sparkle, fire, music, gaming, etc. |
| """ |
| bullet = BULLET_STYLES.get(style, "โฆ") |
| lines = [] |
| |
| for i, item in enumerate(items, 1): |
| if numbered: |
| lines.append(f"**{i}.** {bullet} {item}") |
| else: |
| lines.append(f"{bullet} {item}") |
| |
| return "\n".join(lines) |
|
|
|
|
| def banner_text(text: str, style: str = "neon") -> str: |
| """Create a beautiful banner text with multiple styles. |
| |
| Styles: neon, fire, ice, rainbow, galaxy, cyber, elegant, gaming, music |
| """ |
| styles = { |
| "neon": f"โโโโ **{text}** โโโโ", |
| "fire": f"๐ฅ โโโโโโโ **{text}** โโโโโโโ ๐ฅ", |
| "ice": f"โ๏ธ โโโโโโโโโ **{text}** โโโโโโโโโ โ๏ธ", |
| "rainbow": f"๐ โโโโโโโโโโ **{text}** โโโโโโโโโโ ๐", |
| "galaxy": f"๐ โโโโโโโโ **{text}** โโโโโโโโ ๐", |
| "cyber": f"โก โโโโโโโโ **{text}** โโโโโโโโ โก", |
| "elegant": f"โจ โโโโโโโโโโ **{text}** โโโโโโโโโโ โจ", |
| "gaming": f"๐ฎ โโโโโโโ **{text}** โโโโโโโ ๐ฎ", |
| "music": f"๐ต ~~~~~~~ **{text}** ~~~~~~~ ๐ต", |
| "crown": f"๐ โโโโโโโโโ **{text}** โโโโโโโโโ ๐", |
| "diamond": f"๐ โโโโโโโโโ **{text}** โโโโโโโโโ ๐", |
| "trophy": f"๐ โโโโโ **{text}** โโโโโ ๐", |
| } |
| return styles.get(style, styles["neon"]) |
|
|
|
|
| def category_header(category_name: str, emoji: str, count: int = 0) -> str: |
| """Create a beautiful category header with count.""" |
| if count > 0: |
| return f"โญโ {emoji} **{category_name}** โโฎ\nโ ๐ `{count}` commands available\nโฐโโโโโโโโโโโโโโโฏ" |
| return f"โญโ {emoji} **{category_name}** โโฎ\nโฐโโโโโโโโโโโโโโโฏ" |
|
|
|
|
| def divider_emoji(style: str = "wave", length: int = 10) -> str: |
| """Create a beautiful emoji-based divider. |
| |
| Styles: wave, sparkle, fire, heart, star, diamond, moon, sun, rainbow, gaming, music |
| """ |
| dividers = { |
| "wave": " ๐ ", |
| "sparkle": " โจ ", |
| "fire": " ๐ฅ ", |
| "heart": " ๐ ", |
| "star": " โ
", |
| "diamond": " ๐ ", |
| "moon": " ๐ ", |
| "sun": " โ๏ธ ", |
| "rainbow": " ๐ ", |
| "gaming": " ๐ฎ ", |
| "music": " ๐ต ", |
| "trophy": " ๐ ", |
| "crown": " ๐ ", |
| "rocket": " ๐ ", |
| "lightning": " โก ", |
| "flower": " ๐ธ ", |
| "cloud": " โ๏ธ ", |
| "gem": " ๐ ", |
| } |
| |
| emoji = dividers.get(style, " โฆ ") |
| return emoji * length |
|
|
|
|
| def status_box(status: str, message: str, details: str = "") -> str: |
| """Create a beautiful status box. |
| |
| Status types: success, error, warning, info, loading |
| """ |
| styles = { |
| "success": ("โ
", "<:animatedarrowgreen:1477261279428087979>", NEON_LIME), |
| "error": ("โ", "๐ด", NEON_RED), |
| "warning": ("โ ๏ธ", "<:animatedarrowyellow:1477261257592668271>", NEON_YELLOW), |
| "info": ("โน๏ธ", "๐ต", NEON_BLUE), |
| "loading": ("โณ", "๐ฃ", NEON_PURPLE), |
| } |
| |
| emoji, indicator, _ = styles.get(status, styles["info"]) |
| |
| lines = [ |
| f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| f"โ {emoji} **{message}**", |
| ] |
| |
| if details: |
| lines.append(f"โ โโโโโโโโโโโโโโโโโโโโโ") |
| lines.append(f"โ {details[:50]}") |
| |
| lines.append(f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ") |
| |
| return "\n".join(lines) |
|
|
|
|
| def mini_card(title: str, value: str, emoji: str = "๐") -> str: |
| """Create a mini stat card.""" |
| return f"โญโโโโโโโโโโโโโโโฎ\nโ {emoji} **{title}**\nโ โค `{value}`\nโฐโโโโโโโโโโโโโโโฏ" |
|
|
|
|
| def progress_ring(percentage: int, size: int = 10) -> str: |
| """Create a circular-style progress indicator using emojis.""" |
| if percentage >= 100: |
| return "<:animatedarrowgreen:1477261279428087979>" * size |
| elif percentage >= 75: |
| return "<:animatedarrowgreen:1477261279428087979>" * (size - 2) + "<:animatedarrowyellow:1477261257592668271>" * 2 |
| elif percentage >= 50: |
| return "<:animatedarrowgreen:1477261279428087979>" * (size // 2) + "<:animatedarrowyellow:1477261257592668271>" * (size // 4) + "๐ด" * (size - size // 2 - size // 4) |
| elif percentage >= 25: |
| return "<:animatedarrowyellow:1477261257592668271>" * (size // 4) + "๐ด" * (size - size // 4) |
| else: |
| return "๐ด" * size |
|
|
|
|
| def numbered_list(items: list[str], start: int = 1, emoji_style: str = "sparkle") -> str: |
| """Create a beautifully numbered list with emoji decoration.""" |
| emoji = BULLET_STYLES.get(emoji_style, "โฆ") |
| lines = [] |
| |
| for i, item in enumerate(items, start): |
| lines.append(f"**`{i:02d}`** {emoji} {item}") |
| |
| return "\n".join(lines) |
|
|
|
|
| def table_row(columns: list[str], widths: list[int]) -> str: |
| """Create a table row with specified column widths.""" |
| cells = [] |
| for col, width in zip(columns, widths): |
| cells.append(f" {col[:width-2].ljust(width-2)} ") |
| return "โ".join(cells) |
|
|
|
|
| def table_header(columns: list[str], widths: list[int]) -> str: |
| """Create a table header with separator.""" |
| top = "โ" + "โ" * (widths[0] - 2) + "โฌ" |
| for w in widths[1:-1]: |
| top += "โ" * (w - 2) + "โฌ" |
| top += "โ" * (widths[-1] - 2) + "โ" |
| |
| cells = [] |
| for col, width in zip(columns, widths): |
| cells.append(f" {col[:width-2].ljust(width-2)} ") |
| middle = "โ".join(cells) |
| |
| bottom = "โ" + "โ" * (widths[0] - 2) + "โผ" |
| for w in widths[1:-1]: |
| bottom += "โ" * (w - 2) + "โผ" |
| bottom += "โ" * (widths[-1] - 2) + "โค" |
| |
| return f"{top}\n{middle}\n{bottom}" |
|
|
|
|
| def table_footer(widths: list[int]) -> str: |
| """Create a table footer.""" |
| footer = "โ" + "โ" * (widths[0] - 2) + "โด" |
| for w in widths[1:-1]: |
| footer += "โ" * (w - 2) + "โด" |
| footer += "โ" * (widths[-1] - 2) + "โ" |
| return footer |
|
|
|
|
| def emoji_separator(emoji: str, count: int = 10) -> str: |
| """Create a simple emoji separator line.""" |
| return emoji * count |
|
|
|
|
| def glow_text(text: str, intensity: int = 1) -> str: |
| """Add glow effect to text using special characters.""" |
| glow_chars = ["โ", "โ", "โ", "โ"] |
| prefix = glow_chars[min(intensity, len(glow_chars) - 1)] |
| return f"{prefix * intensity} **{text}** {prefix * intensity}" |
|
|
|
|
| def rainbow_text(text: str) -> str: |
| """Add rainbow effect indication to text.""" |
| colors = ["๐ด", "๐ ", "<:animatedarrowyellow:1477261257592668271>", "<:animatedarrowgreen:1477261279428087979>", "๐ต", "๐ฃ"] |
| return f"{colors[0]}{colors[1]}{colors[2]} **{text}** {colors[3]}{colors[4]}{colors[5]}" |
|
|
|
|
| def sparkle_line(length: int = 20) -> str: |
| """Create a sparkle effect line.""" |
| chars = ["โจ", "โ
", "โ
", "๐ซ", "โฆ"] |
| result = [] |
| import random |
| for _ in range(length): |
| result.append(random.choice(chars)) |
| return " ".join(result) |
|
|
|
|
| def menu_header(title: str, subtitle: str = "", style: str = "default") -> str: |
| """Create a beautiful menu header. |
| |
| Styles: default, cyber, elegant, gaming, neon |
| """ |
| styles = { |
| "default": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\nโ ๐ **{title}**\n{'โ ' + subtitle if subtitle else ''}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| "cyber": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\nโ โก **{title}**\n{'โ ' + subtitle if subtitle else ''}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| "elegant": f"โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ\nโ โจ **{title}**\n{'โ ' + subtitle if subtitle else ''}โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ", |
| "gaming": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\nโ ๐ฎ **{title}**\n{'โ ' + subtitle if subtitle else ''}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| "neon": f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n๐ซ **{title}**\n{' ' + subtitle if subtitle else ''}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ", |
| } |
| return styles.get(style, styles["default"]) |
|
|
|
|
| def quick_stat(label: str, value: str, emoji: str = "๐") -> str: |
| """Create a quick stat display.""" |
| return f"{emoji} **{label}:** `{value}`" |
|
|
|
|
| def quick_stats_grid(stats: list[tuple[str, str, str]], columns: int = 2) -> str: |
| """Create a grid of quick stats. |
| |
| Args: |
| stats: List of (label, value, emoji) tuples |
| columns: Number of columns in the grid |
| """ |
| lines = [] |
| row = [] |
| |
| for label, value, emoji in stats: |
| row.append(f"{emoji} **{label}:** `{value}`") |
| if len(row) >= columns: |
| lines.append(" โ ".join(row)) |
| row = [] |
| |
| if row: |
| lines.append(" โ ".join(row)) |
| |
| return "\n".join(lines) |
|
|
|
|
| |
| COLOR_PRESETS = { |
| "music": NEON_CYAN, |
| "admin": NEON_RED, |
| "fun": NEON_PINK, |
| "utility": NEON_BLUE, |
| "economy": NEON_GOLD, |
| "moderation": NEON_ORANGE, |
| "welcome": NEON_LIME, |
| "giveaway": NEON_MAGENTA, |
| "tournament": NEON_PURPLE, |
| "verification": NEON_TEAL, |
| "ai": NEON_VIOLET, |
| "gaming": NEON_EMERALD, |
| "config": NEON_AMBER, |
| "default": NEON_CYAN, |
| } |
|
|
|
|
| def get_category_color(category: str) -> discord.Color: |
| """Get the appropriate color for a command category.""" |
| return COLOR_PRESETS.get(category.lower(), COLOR_PRESETS["default"]) |
|
|
|
|
| async def add_banner_to_embed(embed: discord.Embed, guild: discord.Guild | None = None, bot = None) -> discord.Embed: |
| """Add server banner to embed if available. |
| |
| This function checks if the guild has a custom banner in the database first, |
| then falls back to Discord's native banner, and finally uses the guild icon as thumbnail. |
| |
| Args: |
| embed: The discord.Embed to add the banner to |
| guild: The discord.Guild to get the banner from |
| bot: The bot instance (optional, for database access) |
| |
| Returns: |
| The modified embed with banner/image |
| """ |
| if guild is None: |
| return embed |
|
|
| |
| if bot is None: |
| state = getattr(guild, "_state", None) |
| get_client = getattr(state, "_get_client", None) |
| if callable(get_client): |
| try: |
| bot = get_client() |
| except Exception: |
| bot = None |
| |
| |
| if bot and getattr(bot, "db", None): |
| try: |
| row = await bot.db.fetchone( |
| "SELECT custom_banner_url FROM guild_config WHERE guild_id = ?", |
| guild.id, |
| ) |
| custom_banner = row[0] if row else None |
| if custom_banner: |
| parsed = urlparse(str(custom_banner)) |
| valid = parsed.scheme in {"http", "https"} and bool(parsed.netloc) |
| valid = valid and str(parsed.path).lower().endswith((".png", ".jpg", ".jpeg", ".webp", ".gif")) |
| if not valid: |
| custom_banner = None |
| if custom_banner: |
| embed.set_image(url=custom_banner) |
| return embed |
| except Exception: |
| pass |
| |
| |
| if guild.banner: |
| embed.set_image(url=guild.banner.url) |
| |
| |
| if guild.icon: |
| embed.set_thumbnail(url=guild.icon.url) |
| |
| return embed |
|
|