From 21fcc410b59808de12e565275d995c56adb1fc2e Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Thu, 19 Mar 2026 13:06:17 -0500 Subject: [PATCH] feat: add ANSI NFO easter egg modal component Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/about/AnsiNfoModal.tsx | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 frontend/src/components/about/AnsiNfoModal.tsx diff --git a/frontend/src/components/about/AnsiNfoModal.tsx b/frontend/src/components/about/AnsiNfoModal.tsx new file mode 100644 index 0000000..751fce1 --- /dev/null +++ b/frontend/src/components/about/AnsiNfoModal.tsx @@ -0,0 +1,182 @@ +import { useEffect, useRef, useState, useCallback } from 'react' +import { + Dialog, + DialogContent, + DialogTitle, +} from '@/components/ui/dialog' +import { APP_VERSION } from '@/lib/version' + +// ── ANSI Art Content ──────────────────────────────────────────────────────── +// Each line is a tuple: [colorClass, text] +// Colors reference Deep Space theme via Tailwind utilities + +const BTC_ADDRESS = 'bc1qfw6pmyc96vrlkpc0rgun0s7xy4sqhx7a2xurkf' + +type ArtLine = [className: string, text: string] + +function buildNfoLines(): ArtLine[] { + const accent = 'text-accent' + const dim = 'text-text-muted' + const secondary = 'text-text-secondary' + const primary = 'text-text-primary' + const bar = '═'.repeat(72) + + return [ + [accent, ''], + [accent, ' ████████╗ ██████╗ ██████╗ '], + [accent, ' ╚══██╔══╝ ██╔═══██╗ ██╔══██╗'], + [accent, ' ██║ ██║ ██║ ██║ ██║'], + [accent, ' ██║ ██║ ██║ ██║ ██║'], + [accent, ' ██║ ╚██████╔╝ ██████╔╝'], + [accent, ' ╚═╝ ╚═════╝ ╚═════╝ '], + [accent, ''], + [dim, ` ${bar}`], + [accent, ''], + [primary, ' ▓▒░ T H E O T H E R D U D E ░▒▓'], + [secondary, ` ${APP_VERSION} · MSP Fleet Management for RouterOS`], + [accent, ''], + [dim, ` ${bar}`], + [dim, ' ░░░ LICENSE ░░░'], + [dim, ` ${bar}`], + [accent, ''], + [primary, ' Business Source License 1.1'], + [accent, ''], + [secondary, ' ► Free self-hosted production use up to 1,000 devices'], + [secondary, ' ► SaaS offering requires commercial agreement'], + [secondary, ' ► Converts to Apache License 2.0 on March 8, 2030'], + [accent, ''], + [dim, ' For commercial licensing: license@theotherdude.net'], + [dim, ' For support: support@theotherdude.net'], + [accent, ''], + [dim, ` ${bar}`], + [dim, ' ░░░ TECH STACK ░░░'], + [dim, ` ${bar}`], + [accent, ''], + [secondary, ' ► Backend ......... Python / FastAPI / PostgreSQL'], + [secondary, ' ► Frontend ........ React / TanStack Router / Tailwind'], + [secondary, ' ► Messaging ....... NATS JetStream'], + [secondary, ' ► VPN ............. WireGuard'], + [secondary, ' ► Deployment ...... Docker Compose / Helm'], + [secondary, ' ► Router Comms .... RouterOS Binary API'], + [accent, ''], + [dim, ` ${bar}`], + [dim, ' ░░░ CREDITS ░░░'], + [dim, ` ${bar}`], + [accent, ''], + [primary, ' Jason Staack'], + [secondary, ' Built with AI assistance'], + [accent, ''], + [dim, ` BTC: ${BTC_ADDRESS}`], + [accent, ''], + [dim, ` ${bar}`], + [accent, ''], + [accent, ' ░▒▓█ t h e o t h e r d u d e . n e t █▓▒░'], + [accent, ''], + [dim, ' "Because every MSP needs one."'], + [accent, ''], + ] +} + +// ── Component ─────────────────────────────────────────────────────────────── + +interface AnsiNfoModalProps { + open: boolean + onOpenChange: (open: boolean) => void +} + +export function AnsiNfoModal({ open, onOpenChange }: AnsiNfoModalProps) { + const [visibleLines, setVisibleLines] = useState(0) + const [animationDone, setAnimationDone] = useState(false) + const linesRef = useRef([]) + const intervalRef = useRef | null>(null) + + if (linesRef.current.length === 0) { + linesRef.current = buildNfoLines() + } + const totalLines = linesRef.current.length + + const skipAnimation = useCallback(() => { + if (intervalRef.current) { + clearInterval(intervalRef.current) + intervalRef.current = null + } + setVisibleLines(totalLines) + setAnimationDone(true) + }, [totalLines]) + + // Start animation when modal opens + useEffect(() => { + if (!open) { + // Reset on close + setVisibleLines(0) + setAnimationDone(false) + if (intervalRef.current) { + clearInterval(intervalRef.current) + intervalRef.current = null + } + return + } + + // Animate lines in + let count = 0 + intervalRef.current = setInterval(() => { + count++ + setVisibleLines(count) + if (count >= totalLines) { + clearInterval(intervalRef.current!) + intervalRef.current = null + setAnimationDone(true) + } + }, 15) + + return () => { + if (intervalRef.current) { + clearInterval(intervalRef.current) + intervalRef.current = null + } + } + }, [open, totalLines]) + + return ( + + { + if (!animationDone && e.key !== 'Escape') { + skipAnimation() + } + }} + onClick={() => { + if (!animationDone) skipAnimation() + }} + > + {/* Retro title bar */} +
+ + TOD.NFO — ACiD View v1.0 + +
+ + {/* Terminal body */} +
+ + {/* Screen-reader accessible version */} +
+

The Other Dude, {APP_VERSION}. MSP Fleet Management for RouterOS.

+

Business Source License 1.1. Free self-hosted production use up to 1000 devices. SaaS requires commercial agreement. Converts to Apache 2.0 on March 8 2030.

+

Built by Jason Staack with AI assistance.

+
+
+
+
+ ) +}