altaf
Version:
Altaf Hossen - Interactive CLI Portfolio
889 lines (781 loc) • 32.6 kB
JavaScript
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const { spawn } = require('child_process');
const { platform } = require('os');
const https = require('https');
const { promisify } = require('util');
// Enhanced color themes
const themes = {
default: {
primary: '\x1b[36m', // cyan
secondary: '\x1b[33m', // yellow
accent: '\x1b[35m', // magenta
success: '\x1b[32m', // green
warning: '\x1b[33m', // yellow
error: '\x1b[31m', // red
info: '\x1b[34m', // blue
text: '\x1b[37m', // white
dim: '\x1b[90m', // gray
bright: '\x1b[1m',
reset: '\x1b[0m'
},
matrix: {
primary: '\x1b[92m', // bright green
secondary: '\x1b[32m', // green
accent: '\x1b[92m', // bright green
success: '\x1b[92m', // bright green
warning: '\x1b[33m', // yellow
error: '\x1b[91m', // bright red
info: '\x1b[92m', // bright green
text: '\x1b[32m', // green
dim: '\x1b[90m', // gray
bright: '\x1b[1m',
reset: '\x1b[0m'
},
cyberpunk: {
primary: '\x1b[95m', // bright magenta
secondary: '\x1b[96m', // bright cyan
accent: '\x1b[93m', // bright yellow
success: '\x1b[92m', // bright green
warning: '\x1b[93m', // bright yellow
error: '\x1b[91m', // bright red
info: '\x1b[94m', // bright blue
text: '\x1b[97m', // bright white
dim: '\x1b[90m', // gray
bright: '\x1b[1m',
reset: '\x1b[0m'
},
professional: {
primary: '\x1b[34m', // blue
secondary: '\x1b[36m', // cyan
accent: '\x1b[35m', // magenta
success: '\x1b[32m', // green
warning: '\x1b[33m', // yellow
error: '\x1b[31m', // red
info: '\x1b[34m', // blue
text: '\x1b[37m', // white
dim: '\x1b[90m', // gray
bright: '\x1b[1m',
reset: '\x1b[0m'
}
};
// Current theme
let currentTheme = 'default';
// Helper function to colorize text with current theme
const colorize = (text, colorType) => {
const theme = themes[currentTheme];
return (theme[colorType] || theme.text) + text + theme.reset;
};
// Animation utilities
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Typewriter effect
async function typeWriter(text, color = 'text', speed = 50) {
for (let i = 0; i < text.length; i++) {
process.stdout.write(colorize(text[i], color));
await sleep(speed);
}
}
// Loading animation
async function showLoading(text, duration = 2000) {
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
let i = 0;
const startTime = Date.now();
const interval = setInterval(() => {
process.stdout.write('\r' + colorize(frames[i % frames.length] + ' ' + text, 'primary'));
i++;
}, 100);
await sleep(duration);
clearInterval(interval);
process.stdout.write('\r' + colorize('✓ ' + text + ' completed!', 'success') + '\n');
}
// Progress bar
async function showProgress(text, steps = 20, duration = 1000) {
process.stdout.write(colorize(text + '\n', 'info'));
for (let i = 0; i <= steps; i++) {
const percent = Math.round((i / steps) * 100);
const filled = '█'.repeat(Math.round(i * 30 / steps));
const empty = '░'.repeat(30 - Math.round(i * 30 / steps));
process.stdout.write('\r' + colorize(`[${filled}${empty}] ${percent}%`, 'primary'));
await sleep(duration / steps);
}
console.log('\n');
}
// Glitch effect for text
function glitchText(text, iterations = 3) {
const glitchChars = '!@#$%^&*()_+-=[]{}|;:,.<>?';
let result = text;
for (let i = 0; i < iterations; i++) {
setTimeout(() => {
let glitched = '';
for (let j = 0; j < text.length; j++) {
if (Math.random() < 0.1) {
glitched += glitchChars[Math.floor(Math.random() * glitchChars.length)];
} else {
glitched += text[j];
}
}
process.stdout.write('\r' + colorize(glitched, 'accent'));
if (i === iterations - 1) {
setTimeout(() => {
process.stdout.write('\r' + colorize(text, 'primary'));
}, 100);
}
}, i * 100);
}
}
// Personal Information
const personalInfo = {
name: 'ALTAF HOSSEN',
title: 'Fullstack Web Developer',
tagline: 'I create Exciting Stuff on the Internet',
bio: `Hey there! 👋🏻
I'm ALTAF, a full stack web developer with a strong passion for crafting digital realms that captivate and inspire.
If you're seeking a dedicated and passionate web developer, I'm eager to collaborate with you. Let's bring your ideas to life!`,
email: 'altafhossen.pro@gmail.com',
github: 'https://github.com/altafhossen-pro',
linkedin: 'https://www.linkedin.com/in/altafhossen',
website: 'https://altaf-hossen.netlify.app',
phone: '+88 013 40 60 30 55',
githubUsername: 'altafhossen-pro' // For API calls
};
// Tech Stack with experience levels
const techStack = {
'Frontend': [
'HTML', 'CSS', 'JavaScript', 'TypeScript', 'React.js', 'Next.js', 'Bootstrap', 'Tailwind CSS', 'GSAP', 'Motion', 'Redux', 'Zustand', 'TS Query', ' React Query', ' React Hook Form', 'Formik', 'Framer Motion', 'Ant Design', 'Material UI', 'Chakra UI', 'Styled Components', 'Emotion'
],
'Backend': [
'Node.js', 'Express.js', 'MongoDB', 'MySQL', 'Firebase', 'PHP', 'REST API', 'GraphQL', 'Socket.io', 'Drive API', 'AWS S3', 'Redis', 'PostgreSQL'
],
'Programming Languages': [
'JavaScript', 'PHP', 'Python'
],
'DevOps': [
'Docker', 'Kubernetes', 'CI/CD', 'GitHub Actions', 'Jenkins', 'Netlify', 'Vercel', 'AWS', 'Azure', 'Heroku', 'DigitalOcean', 'Firebase Hosting', 'Cloudflare', 'NGINX', 'Apache'
],
'Testing': [
'Jest', 'Mocha', 'Chai', 'Cypress', 'Selenium', 'Supertest', 'Enzyme', 'React Testing Library', 'Vitest'
],
'Tools & Technologies': [
'NPM', 'Bun', 'Git', 'GitHub', 'GitLab', 'BitBucket', 'VS Code', 'Figma', 'Postman', 'Swagger', 'Insomnia', 'Webpack', 'Babel', 'ESLint', 'Prettier'
]
};
// Projects with detailed info
const projects = [
{
name: 'Famous Bazar',
description: 'A modern ecommerce website for daily essentials and quality products, featuring secure shopping, discount management, and fast delivery system in all over Bangladesh.',
demo: 'https://famousbazarbd.com',
tech: ["React.js", "Next.js", "Redux", "Node.js", "MongoDB", "Express.js"],
status: 'Live',
year: 2024,
features: ['Payment Integration', 'Admin Panel', 'Real-time Chat', 'Order Tracking']
},
{
name: 'Bongo Courier',
description: 'A modern courier service website for fast, secure, and trackable parcel delivery across Bangladesh, with real-time tracking and efficient parcel management system.',
demo: 'https://bongo-courier.netlify.app',
tech: ['Next.js', 'MongoDB', 'Express.js', 'Tailwind CSS'],
status: 'Live',
year: 2024,
features: ['Real-time Tracking', 'SMS Notifications', 'Route Optimization', 'Mobile App']
},
{
name: 'Parcel Score',
description: 'A smart fraud-checking system to evaluate parcel risk levels using sender history, delivery behavior, and data patterns to prevent misuse and ensure secure courier operations.',
demo: 'https://percelscore.top',
tech: ['React.js', 'Next.js', 'MongoDB', 'REST API'],
status: 'Beta',
year: 2024,
features: ['ML Algorithm', 'Risk Assessment', 'Analytics Dashboard', 'API Integration']
},
{
name: 'Utility Tools',
description: 'A multi-functional web platform offering 30+ fast, secure, and easy-to-use utility tools, designed to simplify daily digital tasks for users across all devices.',
demo: 'https://altaf-tools.netlify.app',
tech: ['JavaScript', 'React.js', 'Next.js'],
status: 'Live',
year: 2023,
features: ['30+ Tools', 'Mobile Responsive', 'No Registration', 'Fast Processing']
},
{
name: 'Rent Management System',
description: 'A powerful bill and rent management system built for Bangladeshi landlords, mess managers, and property owners, featuring subscription plans, real-time tracking, digital payments, and tenant portals.',
demo: 'https://rent-billing.netlify.app',
tech: ['React.js', 'Next.js', 'Node.js', 'MySQL', 'Firebase'],
status: 'Live',
year: 2023,
features: ['Payment Gateway', 'Tenant Portal', 'SMS Alerts', 'Report Generation']
},
{
name: 'Job Portal X',
description: 'A comprehensive job portal system for connecting employers with job seekers, featuring advanced search, application tracking, and profile management.',
demo: 'https://job-portal-x.netlify.app',
tech: ['Next.js', 'React.js', 'Redux', 'Node.js', 'Express.js', 'MongoDB', 'Tailwind CSS'],
status: 'Development',
year: 2024,
features: ['AI Matching', 'Video Interviews', 'Skill Assessment', 'Analytics']
}
];
// GitHub stats cache
let githubStats = null;
let lastFetch = 0;
// Fetch GitHub stats
async function fetchGitHubStats() {
const now = Date.now();
if (githubStats && (now - lastFetch) < 300000) { // 5 minutes cache
return githubStats;
}
return new Promise((resolve) => {
const options = {
hostname: 'api.github.com',
path: `/users/${personalInfo.githubUsername}`,
method: 'GET',
headers: {
'User-Agent': 'CLI-Portfolio'
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
githubStats = {
followers: parsed.followers || 0,
following: parsed.following || 0,
public_repos: parsed.public_repos || 0,
created_at: parsed.created_at || '',
updated_at: parsed.updated_at || ''
};
lastFetch = now;
resolve(githubStats);
} catch (e) {
resolve({ followers: 0, following: 0, public_repos: 0 });
}
});
});
req.on('error', () => {
resolve({ followers: 0, following: 0, public_repos: 0 });
});
req.setTimeout(5000, () => {
req.abort();
resolve({ followers: 0, following: 0, public_repos: 0 });
});
req.end();
});
}
let headerShown = false;
// Enhanced ASCII Art with theme support
function getAsciiArt() {
const fixedMatrix = `
╔═══════════════════════════════════════════════════════════════╗
║ ║
║ █████╗ ██╗ ████████╗ █████╗ ███████╗ ║
║ ██╔══██╗██║ ╚══██╔══╝██╔══██╗██╔════╝ ║
║ ███████║██║ ██║ ███████║█████╗ ║
║ ██╔══██║██║ ██║ ██╔══██║██╔══╝ ║
║ ██║ ██║███████╗██║ ██║ ██║██║ ║
║ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝ ║
║ ║
║ Welcome to my Portfolio Website ║
║ ║
║ FULLSTACK WEB DEVELOPER ║
║ "I create Exciting Stuff on the Internet" ║
║ ║
╚═══════════════════════════════════════════════════════════════╝`;
const arts = {
default: fixedMatrix,
matrix: fixedMatrix,
cyberpunk: fixedMatrix,
};
return arts[currentTheme] || arts.default;
}
// Create readline interface with better handling
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Enhanced keyboard input handling
function setupKeyboardInput() {
if (process.stdin.isTTY) {
process.stdin.setRawMode(true);
}
process.stdin.setEncoding('utf8');
}
// Clear screen function
function clearScreen() {
console.clear();
headerShown = false; // Reset header state when clearing
}
// Show header with animation
async function showHeader() {
if (!headerShown) {
clearScreen();
console.log(colorize(getAsciiArt(), 'primary'));
// console.log(colorize(` ${personalInfo.title}`, 'success'));
// console.log(colorize(` ${personalInfo.tagline}\n`, 'dim'));
headerShown = true;
}
}
// Create enhanced box with better styling
function createBox(text, title = '', color = 'text') {
const lines = text.split('\n');
const maxLength = Math.max(...lines.map(line => line.length), title.length);
const width = Math.max(Math.min(maxLength + 4, 80), 20);
let box = '';
box += colorize('╔' + '═'.repeat(width - 2) + '╗\n', color);
if (title) {
const titlePadding = Math.max(0, Math.floor((width - title.length - 2) / 2));
const rightPadding = Math.max(0, width - title.length - titlePadding - 2);
box += colorize('║' + ' '.repeat(titlePadding) + title + ' '.repeat(rightPadding) + '║\n', color);
box += colorize('╠' + '═'.repeat(width - 2) + '╣\n', color);
}
lines.forEach(line => {
const trimmedLine = line.substring(0, width - 4);
const padding = Math.max(0, width - trimmedLine.length - 2);
box += colorize('║ ' + trimmedLine + ' '.repeat(Math.max(0, padding - 1)) + '║\n', color);
});
box += colorize('╚' + '═'.repeat(width - 2) + '╝\n', color);
return box;
}
// Enhanced about section
async function showAbout() {
await showHeader();
await showLoading('Loading about information', 1000);
console.log(createBox(personalInfo.bio, '👨💻 About Me', 'text'));
console.log(colorize('\nPress Enter to continue...', 'dim'));
}
// Enhanced skills section with progress bars
async function showSkills() {
await showHeader();
await showLoading('Loading skills data', 1200);
console.log(colorize('🚀 Tech Stack & Skills\n', 'primary'));
for (const [category, skills] of Object.entries(techStack)) {
console.log(colorize(`${category}:`, 'secondary'));
// Display skills in a more organized way
const skillsPerLine = 3;
const chunks = [];
for (let i = 0; i < skills.length; i += skillsPerLine) {
chunks.push(skills.slice(i, i + skillsPerLine));
}
chunks.forEach(chunk => {
const line = chunk.map(skill => colorize(`• ${skill}`, 'success')).join(' ');
console.log(` ${line}`);
});
console.log(''); // Empty line between categories
}
// Show total skills count
const totalSkills = Object.values(techStack).flat().length;
console.log(colorize(`📊 Total Skills: ${totalSkills}`, 'info'));
console.log(colorize('\nPress Enter to continue...', 'dim'));
}
// Enhanced projects section
async function showProjects() {
await showHeader();
await showLoading('Fetching project information', 1500);
console.log(colorize('💼 My Projects\n', 'primary'));
for (const [index, project] of projects.entries()) {
const statusColor = project.status === 'Live' ? 'success' :
project.status === 'Beta' ? 'warning' : 'info';
const projectInfo = `${project.description}
Status: ${project.status} | Year: ${project.year}
Tech Stack: ${project.tech.join(', ')}
Features: ${project.features.join(', ')}
Demo: ${project.demo}`;
console.log(createBox(projectInfo, `${index + 1}. ${project.name}`, 'text'));
}
console.log(colorize('\nPress Enter to continue...', 'dim'));
}
// Enhanced contact section with GitHub stats
async function showContact() {
await showHeader();
await showLoading('Fetching contact information', 1000);
console.log(colorize('Fetching GitHub stats...', 'info'));
const stats = await fetchGitHubStats();
const contactInfo = `📧 Email: ${personalInfo.email}
📱 Phone: ${personalInfo.phone}
🌐 Website: ${personalInfo.website}
💼 GitHub: ${personalInfo.github}
🔗 LinkedIn: ${personalInfo.linkedin}
📊 GitHub Stats:
Repositories: ${stats.public_repos}
Followers: ${stats.followers}
Following: ${stats.following}
💬 Let's collaborate!
Contact me to discuss your web development needs
or just to say hello. 😉`;
console.log(createBox(contactInfo, '📞 Contact Information', 'accent'));
console.log(colorize('\nPress Enter to continue...', 'dim'));
}
// Theme selector
async function showThemeSelector() {
await showHeader();
console.log(colorize('🎨 Choose Your Theme\n', 'primary'));
console.log(colorize('1. Default Theme', 'text'));
console.log(colorize('2. Matrix Theme', 'success'));
console.log(colorize('3. Cyberpunk Theme', 'accent'));
console.log(colorize('4. Professional Theme', 'info'));
console.log(colorize('5. Back to Main Menu', 'dim'));
rl.question(colorize('\nEnter your choice (1-5): ', 'secondary'), (answer) => {
handleThemeChoice(answer.trim());
});
}
// Handle theme choice
async function handleThemeChoice(choice) {
const themeMap = {
'1': 'default',
'2': 'matrix',
'3': 'cyberpunk',
'4': 'professional'
};
if (themeMap[choice]) {
currentTheme = themeMap[choice];
await showLoading(`Switching to ${currentTheme} theme`, 1000);
console.log(colorize(`✓ Theme changed to ${currentTheme}!`, 'success'));
setTimeout(() => showMenu(), 1000);
} else if (choice === '5') {
showMenu();
} else {
console.log(colorize('Invalid choice! Please enter 1-5.', 'error'));
setTimeout(() => showThemeSelector(), 1000);
}
}
// Open URL function
function openUrl(url) {
const startCommand = platform() === 'win32' ? 'start' : platform() === 'darwin' ? 'open' : 'xdg-open';
try {
if (platform() === 'win32') {
spawn('cmd', ['/c', 'start', url], { stdio: 'ignore' });
} else {
spawn(startCommand, [url], { stdio: 'ignore' });
}
console.log(colorize(`✓ Opening ${url}...`, 'success'));
} catch (error) {
console.log(colorize(`Please visit: ${url}`, 'warning'));
}
}
// Enhanced main menu
async function showMenu() {
await showHeader();
console.log(colorize('What would you like to know about Altaf?\n', 'primary'));
console.log(colorize('1. 👨💻 About Me', 'text'));
console.log(colorize('2. 🚀 Skills & Tech Stack', 'text'));
console.log(colorize('3. 💼 My Projects', 'text'));
console.log(colorize('4. 📞 Contact Information', 'text'));
console.log(colorize('5. 🎨 Change Theme', 'text'));
console.log(colorize('6. 🌐 Open Website', 'text'));
console.log(colorize('7. 💼 Open GitHub', 'text'));
console.log(colorize('8. 🔗 Open LinkedIn', 'text'));
console.log(colorize('9. ❌ Exit', 'text'));
rl.question(colorize('\nEnter your choice (1-9): ', 'secondary'), (answer) => {
handleMenuChoice(answer.trim());
});
}
// Handle menu choice
async function handleMenuChoice(choice) {
switch (choice) {
case '1':
await showAbout();
rl.question('', () => showMenu());
break;
case '2':
await showSkills();
rl.question('', () => showMenu());
break;
case '3':
await showProjects();
rl.question('', () => showMenu());
break;
case '4':
await showContact();
rl.question('', () => showMenu());
break;
case '5':
showThemeSelector();
break;
case '6':
openUrl(personalInfo.website);
setTimeout(() => showMenu(), 1000);
break;
case '7':
openUrl(personalInfo.github);
setTimeout(() => showMenu(), 1000);
break;
case '8':
openUrl(personalInfo.linkedin);
setTimeout(() => showMenu(), 1000);
break;
case '9':
console.log(colorize('\n🙏 Thanks for checking out my portfolio!', 'secondary'));
console.log(colorize('Have a great day! 👋\n', 'success'));
rl.close();
process.exit(0);
break;
default:
console.log(colorize('Invalid choice! Please enter 1-9.', 'error'));
setTimeout(() => showMenu(), 1000);
}
}
// Handle command line arguments
async function handleArgs() {
const args = process.argv.slice(2);
// Check for theme argument
const themeIndex = args.indexOf('--theme');
if (themeIndex !== -1 && args[themeIndex + 1]) {
const theme = args[themeIndex + 1];
if (themes[theme]) {
currentTheme = theme;
console.log(colorize(`Using ${theme} theme`, 'success'));
}
}
if (args.includes('--about') || args.includes('-a')) {
await showAbout();
rl.question('', () => rl.close());
} else if (args.includes('--skills') || args.includes('-s')) {
await showSkills();
rl.question('', () => rl.close());
} else if (args.includes('--projects') || args.includes('-p')) {
await showProjects();
rl.question('', () => rl.close());
} else if (args.includes('--contact') || args.includes('-c')) {
await showContact();
rl.question('', () => rl.close());
} else if (args.includes('--theme')) {
showThemeSelector();
} else if (args.includes('--help') || args.includes('-h')) {
showHelp();
rl.question('', () => rl.close());
} else {
// Show interactive menu
showMenu();
}
}
// Show enhanced help
function showHelp() {
clearScreen();
console.log(colorize(getAsciiArt(), 'primary'));
const helpText = `Available Commands:
Interactive Mode:
npx altaf Show interactive menu
Direct Commands:
npx altaf --about Show about information
npx altaf --skills Show skills and tech stack
npx altaf --projects Show projects
npx altaf --contact Show contact information
npx altaf --theme Show theme selector
npx altaf --help Show this help message
Theme Options:
npx altaf --theme default Use default theme
npx altaf --theme matrix Use matrix theme
npx altaf --theme cyberpunk Use cyberpunk theme
npx altaf --theme professional Use professional theme
Short flags:
-a, --about About information
-s, --skills Skills and tech stack
-p, --projects Projects
-c, --contact Contact information
-h, --help Help message
Features:
• Multiple color themes
• Animated text effects
• Loading animations
• Progress bars
• Live GitHub stats
• Interactive navigation`;
console.log(createBox(helpText, '📚 Help & Usage', 'info'));
console.log(colorize('\nPress Enter to continue...', 'dim'));
}
// Easter egg - Matrix rain effect
function matrixRain() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()';
const columns = Math.floor(process.stdout.columns / 2);
const drops = new Array(columns).fill(0);
console.log(colorize('Entering the Matrix...', 'success'));
const interval = setInterval(() => {
process.stdout.write('\x1b[2J\x1b[0;0H'); // Clear screen
for (let i = 0; i < drops.length; i++) {
const char = chars[Math.floor(Math.random() * chars.length)];
process.stdout.write('\x1b[' + drops[i] + ';' + (i * 2) + 'H');
process.stdout.write(colorize(char, 'primary'));
if (drops[i] * 2 > process.stdout.rows && Math.random() > 0.975) {
drops[i] = 0;
}
drops[i]++;
}
}, 100);
setTimeout(() => {
clearInterval(interval);
clearScreen();
console.log(colorize('Welcome back to reality!', 'success'));
setTimeout(() => showMenu(), 1000);
}, 5000);
}
// Enhanced startup animation
async function startupAnimation() {
console.log(colorize('Initializing Altaf\'s Portfolio...', 'primary'));
await showProgress('Loading modules', 15, 800);
await showProgress('Connecting to GitHub API', 10, 500);
await showProgress('Setting up themes', 8, 400);
await showProgress('Ready to launch', 5, 300);
console.log(colorize('✓ Portfolio loaded successfully!', 'success'));
await sleep(500);
}
// System information
function getSystemInfo() {
const os = require('os');
return {
platform: os.platform(),
arch: os.arch(),
nodeVersion: process.version,
uptime: Math.floor(process.uptime()),
memory: Math.round(process.memoryUsage().heapUsed / 1024 / 1024)
};
}
// Show system info (hidden feature)
function showSystemInfo() {
const info = getSystemInfo();
const sysInfo = `Platform: ${info.platform}
Architecture: ${info.arch}
Node.js Version: ${info.nodeVersion}
Uptime: ${info.uptime}s
Memory Usage: ${info.memory}MB
Current Theme: ${currentTheme}
GitHub Cache: ${githubStats ? 'Active' : 'Empty'}`;
console.log(createBox(sysInfo, '🔧 System Information', 'info'));
}
// Enhanced menu with hidden features
async function showEnhancedMenu() {
await showHeader();
console.log(colorize('What would you like to know about Altaf?\n', 'primary'));
console.log(colorize('1. 👨💻 About Me', 'text'));
console.log(colorize('2. 🚀 Skills & Tech Stack', 'text'));
console.log(colorize('3. 💼 My Projects', 'text'));
console.log(colorize('4. 📞 Contact Information', 'text'));
console.log(colorize('5. 🎨 Change Theme', 'text'));
console.log(colorize('6. 🌐 Open Website', 'text'));
console.log(colorize('7. 💼 Open GitHub', 'text'));
console.log(colorize('8. 🔗 Open LinkedIn', 'text'));
console.log(colorize('9. ❌ Exit', 'text'));
console.log(colorize('\nHidden: matrix, sys, glitch', 'dim'));
rl.question(colorize('\nEnter your choice: ', 'secondary'), (answer) => {
handleEnhancedMenuChoice(answer.trim().toLowerCase());
});
}
// Handle enhanced menu choices with easter eggs
async function handleEnhancedMenuChoice(choice) {
switch (choice) {
case '1':
await showAbout();
rl.question('', () => showEnhancedMenu());
break;
case '2':
await showSkills();
rl.question('', () => showEnhancedMenu());
break;
case '3':
await showProjects();
rl.question('', () => showEnhancedMenu());
break;
case '4':
await showContact();
rl.question('', () => showEnhancedMenu());
break;
case '5':
showThemeSelector();
break;
case '6':
openUrl(personalInfo.website);
setTimeout(() => showEnhancedMenu(), 1000);
break;
case '7':
openUrl(personalInfo.github);
setTimeout(() => showEnhancedMenu(), 1000);
break;
case '8':
openUrl(personalInfo.linkedin);
setTimeout(() => showEnhancedMenu(), 1000);
break;
case '9':
console.log(colorize('\n🙏 Thanks for checking out my portfolio!', 'secondary'));
console.log(colorize('Have a great day! 👋\n', 'success'));
rl.close();
process.exit(0);
break;
// Easter eggs
case 'matrix':
matrixRain();
break;
case 'sys':
case 'system':
showSystemInfo();
rl.question(colorize('\nPress Enter to continue...', 'dim'), () => showEnhancedMenu());
break;
case 'glitch':
console.log('');
glitchText(personalInfo.name, 5);
setTimeout(() => {
console.log('\n');
showEnhancedMenu();
}, 2000);
break;
default:
console.log(colorize('Invalid choice! Please try again.', 'error'));
setTimeout(() => showEnhancedMenu(), 1000);
}
}
// Update the main menu function to use enhanced menu
async function showMenu() {
await showEnhancedMenu();
}
// Visitor counter (simple file-based)
function updateVisitorCount() {
const counterFile = path.join(__dirname, '.visitor_count');
let count = 0;
try {
if (fs.existsSync(counterFile)) {
count = parseInt(fs.readFileSync(counterFile, 'utf8')) || 0;
}
count++;
fs.writeFileSync(counterFile, count.toString());
return count;
} catch (error) {
return 1;
}
}
// Welcome message with visitor count
async function showWelcome() {
const visitorCount = updateVisitorCount();
console.log(colorize(`Welcome! You are visitor #${visitorCount}`, 'info'));
await sleep(1000);
}
// Start the application
async function startApplication() {
try {
setupKeyboardInput();
await showWelcome();
await startupAnimation();
await handleArgs();
} catch (error) {
console.log(colorize('Error starting application:', 'error'));
console.log(colorize(error.message, 'error'));
process.exit(1);
}
}
// Handle process exit with style
process.on('SIGINT', async () => {
console.log(colorize('\n\n🙏 Thanks for checking out my portfolio!', 'secondary'));
await typeWriter('Have a great day! 👋', 'success', 50);
console.log('\n');
process.exit(0);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.log(colorize('\nAn error occurred:', 'error'));
console.log(colorize(error.message, 'error'));
console.log(colorize('\nPlease try again or report this issue.', 'warning'));
process.exit(1);
});
// Start the application
startApplication();