Files

236 lines
9.0 KiB
Python
Executable File

"""
utils/embeds.py — cyberpunk / hacker-aesthetic embed builders for RepoRadar.
Every embed is built here so styling stays consistent: dark backdrops, neon
accent colours, monospace code blocks, and tidy mobile + desktop formatting.
Functions accept the normalised `Repo` dataclass from utils.git_api and return
ready-to-send nextcord.Embed objects.
"""
from __future__ import annotations
from datetime import datetime, timezone
import nextcord
from config import settings
from utils.git_api import Repo
from utils.helpers import discord_timestamp, truncate
BRAND = "RepoRadar // Project Intelligence"
def _footer(embed: nextcord.Embed) -> nextcord.Embed:
embed.set_footer(text=f"⛓ {BRAND}")
embed.timestamp = datetime.now(timezone.utc)
return embed
# ──────────────────────────────────────────────────────────────
# Error / utility embeds
# ──────────────────────────────────────────────────────────────
def build_error_embed(title: str, message: str) -> nextcord.Embed:
embed = nextcord.Embed(
title=f"⛔ {title}",
description=message,
color=settings.color_error,
)
return _footer(embed)
def build_info_embed(title: str, message: str) -> nextcord.Embed:
embed = nextcord.Embed(
title=f"✅ {title}",
description=message,
color=settings.color_success,
)
return _footer(embed)
# ──────────────────────────────────────────────────────────────
# Project-drop embeds
# ──────────────────────────────────────────────────────────────
def _lang_emoji(language: str) -> str:
"""A glanceable marker for the repo's primary language."""
return {
"python": "🐍", "go": "🐹", "rust": "🦀", "c": "🔧", "c++": "🔧",
"java": "☕", "javascript": "🟨", "typescript": "🔷", "shell": "🐚",
"ruby": "💎", "php": "🐘", "html": "🌐", "powershell": "💠",
}.get((language or "").lower(), "📦")
def build_repo_drop_embed(
repo: Repo,
*,
votes: dict[str, int] | None = None,
watch_label: str | None = None,
highlight: bool = False,
admin_note: str | None = None,
) -> nextcord.Embed:
"""The card posted when a brand-new project is discovered on the git server."""
votes = votes or {"up": 0, "down": 0, "score": 0}
title_prefix = "🌟 FEATURED DROP" if highlight else "🆕 NEW PROJECT"
embed = nextcord.Embed(
title=f"{_lang_emoji(repo.language)} {truncate(repo.full_name or repo.name, 240)}",
url=repo.url or None,
description=truncate(repo.description or "*No description provided.*", 1024),
color=settings.color_highlight if highlight else settings.color_drop,
)
embed.set_author(name=f"⛓ {title_prefix}")
embed.add_field(name="◈ Owner", value=f"`{repo.owner or 'unknown'}`", inline=True)
if repo.language:
embed.add_field(name="◈ Language", value=f"`{repo.language}`", inline=True)
embed.add_field(
name="◈ Created",
value=discord_timestamp(repo.created_at, "R"),
inline=True,
)
embed.add_field(name="◈ ⭐ Stars", value=f"`{repo.stars}`", inline=True)
embed.add_field(name="◈ 🍴 Forks", value=f"`{repo.forks}`", inline=True)
embed.add_field(
name="◈ 🗳 Community",
value=f"👍 `{votes['up']}` 👎 `{votes['down']}` • net `{votes['score']:+d}`",
inline=True,
)
if repo.topics:
embed.add_field(
name="◈ Topics",
value=" ".join(f"`{t}`" for t in repo.topics[:10]),
inline=False,
)
if admin_note:
embed.add_field(name="◈ Curator Note", value=truncate(admin_note, 1024), inline=False)
if watch_label:
embed.add_field(name="◈ Source", value=watch_label, inline=False)
if repo.url:
embed.add_field(name="◈ Repository", value=f"[🔗 Open project]({repo.url})", inline=False)
return _footer(embed)
def build_repo_list_embed(
repos: list[Repo],
*,
title: str = "🛰 LATEST PROJECTS",
limit: int = 10,
) -> nextcord.Embed:
"""Compact chronological list of the newest repositories (newest first)."""
embed = nextcord.Embed(
title=f"☣ {title}",
description=(
"```ansi\n\u001b[1;35m> Freshest projects from the git server\u001b[0m\n```"
f"Showing the **{min(limit, len(repos))}** most recent."
),
color=settings.color_drop,
)
for repo in repos[:limit]:
created = discord_timestamp(repo.created_at, "R")
meta = f"⭐ {repo.stars} · 🍴 {repo.forks}"
if repo.language:
meta = f"`{repo.language}` · " + meta
desc = truncate(repo.description or "*No description.*", 130)
link = f"[open]({repo.url})" if repo.url else ""
embed.add_field(
name=f"{_lang_emoji(repo.language)} {truncate(repo.full_name or repo.name, 60)}",
value=f"{desc}\n{meta} · {created} · {link}",
inline=False,
)
if not repos:
embed.description = "No projects could be retrieved right now."
return _footer(embed)
def build_git_leaderboard_embed(rows: list[dict], *, limit: int = 10) -> nextcord.Embed:
"""Top community-voted projects."""
embed = nextcord.Embed(
title="🏆 COMMUNITY TOP PROJECTS",
description="```ansi\n\u001b[1;32m> Ranked by community vote score\u001b[0m\n```",
color=settings.color_success,
)
medals = {0: "🥇", 1: "🥈", 2: "🥉"}
for i, row in enumerate(rows[:limit]):
name = row.get("full_name") or row.get("repo_key", "unknown")
url = row.get("url") or ""
score = int(row.get("score") or 0)
up = int(row.get("up") or 0)
down = int(row.get("down") or 0)
marker = medals.get(i, f"`#{i + 1}`")
link = f"[open]({url})" if url else ""
embed.add_field(
name=f"{marker} {truncate(name, 60)}",
value=f"net `{score:+d}` • 👍 `{up}` 👎 `{down}` {link}",
inline=False,
)
if not rows:
embed.description = "No votes have been cast yet. Be the first to vote on a drop!"
return _footer(embed)
def build_git_status_embed(
*,
provider: str,
base_url: str,
configured: bool,
drop_channel_id: int | None,
highlight_channel_id: int | None,
highlight_role_id: int | None,
min_stars: int,
keywords: str,
enabled: bool,
watches: list[dict],
poll_interval: int,
) -> nextcord.Embed:
"""Render the current monitor configuration for a guild."""
embed = nextcord.Embed(
title="⚙ REPORADAR — CONFIGURATION",
color=settings.color_drop if configured else settings.color_medium,
)
status = "🟢 enabled" if enabled else "🔴 disabled"
embed.add_field(name="◈ Provider", value=f"`{provider or 'unconfigured'}`", inline=True)
embed.add_field(name="◈ Server", value=f"`{base_url or 'api.github.com'}`", inline=True)
embed.add_field(name="◈ Monitor", value=status, inline=True)
embed.add_field(
name="◈ Drop channel",
value=f"<#{drop_channel_id}>" if drop_channel_id else "`not set`",
inline=True,
)
embed.add_field(
name="◈ Highlight channel",
value=f"<#{highlight_channel_id}>" if highlight_channel_id else "`not set`",
inline=True,
)
embed.add_field(
name="◈ Highlight role",
value=f"<@&{highlight_role_id}>" if highlight_role_id else "`none`",
inline=True,
)
embed.add_field(name="◈ Min ⭐ to highlight", value=f"`{min_stars}`", inline=True)
embed.add_field(name="◈ Poll interval", value=f"`{poll_interval}s`", inline=True)
embed.add_field(
name="◈ Highlight keywords",
value=f"`{keywords}`" if keywords else "`none`",
inline=False,
)
if watches:
lines = []
for w in watches:
scope = w["scope_type"]
val = w["scope_value"] or "*entire server*"
ch = f" → <#{w['channel_id']}>" if w.get("channel_id") else ""
lines.append(f"• `{scope}` **{val}**{ch}")
embed.add_field(name="◈ Active watches", value=truncate("\n".join(lines), 1024), inline=False)
else:
embed.add_field(
name="◈ Active watches",
value="None yet — add one with `/radar_watch`.",
inline=False,
)
return _footer(embed)