|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Neon ASCII Dashboard: hot pink on black; adorable and helpful. |
| 3 | + |
| 4 | +import os, sys, time, webbrowser, subprocess, platform |
| 5 | +from pathlib import Path |
| 6 | + |
| 7 | +# ANSI helpers |
| 8 | +RESET = "\033[0m" |
| 9 | +PINK = "\033[38;5;205m" |
| 10 | +BLACK_BG = "\033[48;5;232m" |
| 11 | +BOLD = "\033[1m" |
| 12 | +DIM = "\033[2m" |
| 13 | + |
| 14 | +ASCII_LOGO = r""" |
| 15 | + __ __ _ _ _ _ _ _ |
| 16 | +| \/ | __ _| | _____| | | |_| | __ _| |_ ___ |
| 17 | +| |\/| |/ _` | |/ / _ \ | | __| |/ _` | __/ _ \ |
| 18 | +| | | | (_| | < __/ | | |_| | (_| | || __/ |
| 19 | +|_| |_|\__,_|_|\_\___|_|_|\__|_|\__,_|\__\___| |
| 20 | + Python for Baddies · make it cute |
| 21 | +""" |
| 22 | + |
| 23 | +MENU = [ |
| 24 | + ("Create/activate venv", "create_venv"), |
| 25 | + ("Install requirements", "install_requirements"), |
| 26 | + ("Run a friendly REPL (rich)", "run_repl"), |
| 27 | + ("Open docs (OS setup)", "open_docs"), |
| 28 | + ("Open GitHub repo", "open_repo"), |
| 29 | + ("Social pointables", "social_links"), |
| 30 | + ("Tiny tutor: tips & tricks", "tiny_tips"), |
| 31 | + ("Quit", "quit"), |
| 32 | +] |
| 33 | + |
| 34 | +ROOT = Path(__file__).resolve().parents[2] |
| 35 | +DOCS = ROOT / "docs" |
| 36 | +REPO_URL = "https://github.com/dascient/makeitcute" |
| 37 | + |
| 38 | +SOCIAL = { |
| 39 | + "Discord": "https://discord.gg/your_invite", |
| 40 | + "TikTok": "https://www.tiktok.com/@your_handle", |
| 41 | + "Instagram": "https://www.instagram.com/your_handle", |
| 42 | + "X/Twitter": "https://twitter.com/your_handle", |
| 43 | + "YouTube": "https://youtube.com/@your_handle", |
| 44 | +} |
| 45 | + |
| 46 | +def clear(): |
| 47 | + os.system("cls" if os.name == "nt" else "clear") |
| 48 | + |
| 49 | +def print_header(): |
| 50 | + print(f"{BLACK_BG}{PINK}{BOLD}{ASCII_LOGO}{RESET}") |
| 51 | + print(f"{PINK}{DIM}Hot pink. Pure black. Egregiously charming.{RESET}\n") |
| 52 | + |
| 53 | +def prompt(menu): |
| 54 | + for idx, (label, _) in enumerate(menu, 1): |
| 55 | + print(f"{PINK}{idx:>2}. {label}{RESET}") |
| 56 | + print() |
| 57 | + val = input(f"{BOLD}{PINK}Choose an option: {RESET}") |
| 58 | + return int(val) if val.isdigit() and 1 <= int(val) <= len(menu) else 0 |
| 59 | + |
| 60 | +def open_file(path: Path): |
| 61 | + if os.name == "nt": |
| 62 | + os.startfile(str(path)) |
| 63 | + elif sys.platform == "darwin": |
| 64 | + subprocess.run(["open", str(path)]) |
| 65 | + else: |
| 66 | + subprocess.run(["xdg-open", str(path)]) |
| 67 | + |
| 68 | +def create_venv(): |
| 69 | + venv = ROOT / ".venv" |
| 70 | + if not venv.exists(): |
| 71 | + subprocess.check_call([sys.executable, "-m", "venv", str(venv)]) |
| 72 | + print(f"{PINK}✨ Created .venv{RESET}") |
| 73 | + else: |
| 74 | + print(f"{PINK}✔ .venv already exists{RESET}") |
| 75 | + activate_msg = ".venv\\Scripts\\Activate.ps1" if os.name == "nt" else "source .venv/bin/activate" |
| 76 | + print(f"{DIM}Activate with: {activate_msg}{RESET}") |
| 77 | + input(f"{PINK}Press Enter to continue…{RESET}") |
| 78 | + |
| 79 | +def install_requirements(): |
| 80 | + req = ROOT / "requirements.txt" |
| 81 | + subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "pip"]) |
| 82 | + subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", str(req)]) |
| 83 | + print(f"{PINK}🧁 Requirements installed!{RESET}") |
| 84 | + input(f"{PINK}Press Enter to continue…{RESET}") |
| 85 | + |
| 86 | +def run_repl(): |
| 87 | + banner = f"{PINK}Welcome to the Friendly REPL. Try: print('hiya 💖') {RESET}" |
| 88 | + try: |
| 89 | + import code |
| 90 | + code.interact(banner=banner, local={}) |
| 91 | + except Exception as e: |
| 92 | + print(f"{PINK}REPL failed: {e}{RESET}") |
| 93 | + input(f"{PINK}Press Enter to continue…{RESET}") |
| 94 | + |
| 95 | +def open_docs(): |
| 96 | + plat = platform.system().lower() |
| 97 | + target = { |
| 98 | + "darwin": DOCS / "INSTALL-macOS.md", |
| 99 | + "windows": DOCS / "INSTALL-windows.md", |
| 100 | + "linux": DOCS / "INSTALL-linux.md", |
| 101 | + }.get(plat, DOCS) |
| 102 | + try: |
| 103 | + open_file(target) |
| 104 | + except Exception: |
| 105 | + webbrowser.open(REPO_URL + "/tree/main/docs") |
| 106 | + |
| 107 | +def open_repo(): |
| 108 | + webbrowser.open(REPO_URL) |
| 109 | + |
| 110 | +def social_links(): |
| 111 | + print(f"{PINK}{BOLD}Social pointables:{RESET}") |
| 112 | + for name, url in SOCIAL.items(): |
| 113 | + print(f" - {name}: {url}") |
| 114 | + print("\nTip: replace the placeholders in neon_dash.py → SOCIAL dict.") |
| 115 | + input(f"{PINK}Press Enter to continue…{RESET}") |
| 116 | + |
| 117 | +def tiny_tips(): |
| 118 | + tips = [ |
| 119 | + "Use `python -m pip` to avoid version confusion.", |
| 120 | + "Name venv `.venv` so editors auto-detect it.", |
| 121 | + "Run `python -m http.server` to share a folder locally.", |
| 122 | + "Use f-strings for readable formatting: f'{2+2=}' → 2+2=4", |
| 123 | + "pip freeze > requirements.txt to capture deps.", |
| 124 | + ] |
| 125 | + for t in tips: |
| 126 | + print(f"{PINK}• {t}{RESET}") |
| 127 | + input(f"{PINK}Press Enter to continue…{RESET}") |
| 128 | + |
| 129 | +def quit(): |
| 130 | + print(f"{PINK}Stay cute, stay curious. Bye!{RESET}") |
| 131 | + sys.exit(0) |
| 132 | + |
| 133 | +def main(): |
| 134 | + while True: |
| 135 | + clear() |
| 136 | + print_header() |
| 137 | + choice = prompt(MENU) |
| 138 | + if choice == 0: |
| 139 | + continue |
| 140 | + _, fn = MENU[choice-1] |
| 141 | + globals()[fn]() |
| 142 | + |
| 143 | +if __name__ == "__main__": |
| 144 | + main() |
0 commit comments