Files
djinit/djinit/ui/console.py
T

181 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Console UI utilities for djinit.
Provides clean, minimal styling and user interface components.
"""
from contextlib import contextmanager
from typing import Any, Dict, List, Optional
from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn
from rich.table import Table
from rich.text import Text
console = Console()
class UIColors:
"""Color scheme for consistent UI styling"""
SUCCESS = "bold green"
ERROR = "bold red"
WARNING = "bold yellow"
INFO = "bold blue"
HIGHLIGHT = "bold cyan"
MUTED = "dim white"
ACCENT = "bold magenta"
CODE = "bold white"
class Icons:
"""Minimal icon set"""
SUCCESS = "✓"
ERROR = "✗"
WARNING = "⚠"
INFO = "ℹ"
ROCKET = "🚀"
TARGET = "🎯"
LINK = "🔗"
CLOCK = "⏱"
PARTY = "🎉"
class UIFormatter:
"""Utility class for consistent UI formatting"""
@staticmethod
def print_success(message: str, icon: str = Icons.SUCCESS):
"""Print success message"""
console.print(f"[{UIColors.SUCCESS}]{icon}[/{UIColors.SUCCESS}] [bold]{message}[/bold]")
@staticmethod
def print_error(message: str, icon: str = Icons.ERROR, details: Optional[str] = None):
"""Print error message with optional details"""
console.print(f"[{UIColors.ERROR}]{icon}[/{UIColors.ERROR}] [bold]{message}[/bold]")
if details:
console.print(f" [dim]{details}[/dim]")
@staticmethod
def print_warning(message: str, icon: str = Icons.WARNING):
"""Print warning message"""
console.print(f"[{UIColors.WARNING}]{icon}[/{UIColors.WARNING}] [bold]{message}[/bold]")
@staticmethod
def print_info(message: str, icon: str = ""):
"""Print info message"""
if icon:
console.print(f"[{UIColors.INFO}]{icon}[/{UIColors.INFO}] [bold]{message}[/bold]")
else:
console.print(f"[{UIColors.INFO}]{message}[/{UIColors.INFO}]")
@staticmethod
def create_live_progress(description: str = "Setup Progress", total_steps: int = 100):
"""Create a live progress display"""
progress = Progress(
SpinnerColumn(),
TextColumn("[bold blue]{task.description}"),
BarColumn(bar_width=40),
TaskProgressColumn(),
console=console,
)
task = progress.add_task(description, total=total_steps)
return progress, task
@staticmethod
def print_header(text: str, style: str = UIColors.ACCENT):
"""Print a styled header"""
console.print(f"\n[{style}]{'═' * 70}[/{style}]")
console.print(f"[{style}]{text.center(70)}[/{style}]")
console.print(f"[{style}]{'═' * 70}[/{style}]\n")
@staticmethod
def print_separator(char: str = "─", width: int = 70, style: str = UIColors.MUTED):
"""Print a visual separator"""
console.print(f"[{style}]{char * width}[/{style}]")
@staticmethod
def print_panel(content: str, title: str = "", border_style: str = "blue"):
"""Print content in a styled panel"""
panel = Panel(content, title=title, border_style=border_style, box=box.ROUNDED, padding=(1, 2))
console.print(panel)
@staticmethod
def print_table(data: List[Dict[str, Any]], title: Optional[str] = None):
"""Print data in a styled table"""
if not data:
return
table = Table(title=title, box=box.ROUNDED, show_header=True, header_style="bold cyan")
for key in data[0].keys():
table.add_column(key.replace("_", " ").title(), style="white")
for row in data:
table.add_row(*[str(v) for v in row.values()])
console.print(table)
@staticmethod
def create_welcome_panel():
"""Create a minimal welcome panel"""
welcome_text = Text()
welcome_text.append("\n ╔═══════════════════════════════════════╗\n", style=UIColors.ACCENT)
welcome_text.append(" ║ Django Init (djinit) ║\n", style=UIColors.ACCENT)
welcome_text.append(" ╚═══════════════════════════════════════╝\n\n", style=UIColors.ACCENT)
welcome_text.append(" Create production-ready Django projects\n\n", style=UIColors.MUTED)
welcome_text.append(" Repository: ", style=UIColors.MUTED)
welcome_text.append("https://github.com/S4NKALP/djinit\n", style="blue underline")
return welcome_text
@staticmethod
def create_summary_panel(
project_dir: str,
project_name: str,
app_names: List[str],
success: bool,
duration: Optional[float] = None,
metadata: Optional[Dict[str, Any]] = None,
):
"""Create a minimal completion summary"""
if success:
console.print("\n")
console.print(f"[bold green]{'═' * 70}[/bold green]")
console.print(f"[bold green]{f'{Icons.PARTY} SETUP COMPLETE'.center(70)}[/bold green]")
console.print(f"[bold green]{'═' * 70}[/bold green]\n")
else:
console.print("\n")
console.print(f"[bold red]{'═' * 70}[/bold red]")
console.print(f"[bold red]{'❌ SETUP FAILED'.center(70)}[/bold red]")
console.print(f"[bold red]{'═' * 70}[/bold red]\n")
console.print("[red]Setup encountered an error. Check messages above.[/red]\n")
console.print(f"[bold red]{'═' * 70}[/bold red]\n")
@staticmethod
@contextmanager
def status(message: str, spinner: str = "dots"):
"""Context manager for status display"""
with console.status(f"[bold cyan]{message}...", spinner=spinner):
yield
@staticmethod
def confirm(prompt: str, default: bool = True) -> bool:
"""Display a confirmation prompt"""
default_str = "Y/n" if default else "y/N"
response = console.input(f"[bold cyan]?[/bold cyan] {prompt} [{default_str}]: ").strip().lower()
if not response:
return default
return response in ("y", "yes")
@staticmethod
def prompt(message: str, default: Optional[str] = None) -> str:
"""Display an input prompt"""
if default:
message = f"{message} [{default}]"
response = console.input(f"[bold cyan]?[/bold cyan] {message}: ").strip()
return response or default or ""