diff --git a/README.md b/README.md index 65ad2e1..c914ffa 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Type the following commands inside the terminal: * **GitHub**: [https://github.com/skvprogrammer](https://github.com/skvprogrammer) * **LeetCode**: [https://leetcode.com/u/skvprogrammer](https://leetcode.com/u/skvprogrammer) * **Linktree**: [https://linktr.ee/skvprogrammer](https://linktr.ee/skvprogrammer) -* **Omezle**: [https://omezle.fun](https://omezle.fun) +* **Omezle**: [https://omezle.xyz](https://omezle.xyz) --- diff --git a/src/components/Terminal.js b/src/components/Terminal.js index f00b114..9abc7e6 100644 --- a/src/components/Terminal.js +++ b/src/components/Terminal.js @@ -1,430 +1,793 @@ -import React, { useState } from "react"; -import { motion } from "framer-motion"; -import { FaSun, FaMoon,FaChevronRight } from "react-icons/fa"; -import { TypeAnimation } from "react-type-animation"; -import styled from "styled-components"; - - -const TerminalContainer = styled.div` - background: ${(props) => (props.theme === "dark" ? "#1e1e1e" : "#f9f9f9")}; - color: ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; - width: 90%; - height: 80vh; - margin: 0 auto; /* Removed 50px margin to center vertically */ - padding: 20px; - font-family: "Courier New", Courier, monospace; - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - border-radius: 10px; - display: flex; - flex-direction: column; - position: relative; - top: 45%; - transform: translateY(-50%); -`; - - -const TerminalHeader = styled.div` - background: ${(props) => (props.theme === "dark" ? "#2c2c2c" : "#ddd")}; - color: ${(props) => (props.theme === "dark" ? "#fff" : "#000")}; - padding: 10px 20px; - font-size: 14px; - display: flex; - justify-content: space-between; - align-items: center; - border-radius: 10px 10px 0 0; - flex-direction: column; - gap: 10px; -`; - -// const HeaderButtons = styled.div` -// display: flex; -// gap: 8px; - -// span { -// width: 12px; -// height: 12px; -// border-radius: 50%; -// display: inline-block; -// background: ${(props) => props.color}; -// } -// `; - -// const Menu = styled.div` -// display: flex; -// gap: 20px; - -// a { -// text-decoration: none; -// color: ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; -// font-weight: bold; -// transition: color 0.3s; - -// &:hover { -// color: ${(props) => (props.theme === "dark" ? "#fff" : "#000")}; -// } -// } -// `; - - -const TerminalBody = styled.div` - flex: 1; - overflow-y: auto; - margin-top: 10px; -`; - -const Line = styled.div` - display: flex; - align-items: center; - gap: 10px; -`; - -const Prompt = styled.span` - font-family: "Courier New", Courier, monospace; - color: ${(props) => (props.theme === "dark" ? "#ff0000" : "#990000")}; - font-weight: 700; - font-size: 0.95rem; -`; - -const Cursor = styled.span` - background: ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; - width: 8px; - height: 16px; - display: inline-block; - animation: blink 0.8s infinite; - @keyframes blink { - 0%, 50% { - opacity: 1; +import React, { useState, useRef, useEffect, useCallback } from "react"; + +const THEMES = { + dark: { + bg: "#080b19", + headerBg: "#0d1126", + footerBg: "#0d1126", + text: "#c8ffd4", + accent: "#00ff88", + accentDim: "#00cc6a", + prompt: "#00bfff", + error: "#ff4d6d", + muted: "#445566", + border: "rgba(0,255,136,0.12)", + headerText: "#7effd4", + buttonBg: "rgba(0,255,136,0.08)", + buttonHover: "rgba(0,255,136,0.18)", + link: "#00e5ff", + }, + light: { + bg: "#f4f6f0", + headerBg: "#e8ede2", + footerBg: "#e8ede2", + text: "#1a2e1a", + accent: "#1a7a40", + accentDim: "#2a9a55", + prompt: "#1a5a8a", + error: "#c0392b", + muted: "#7a8a7a", + border: "rgba(26,122,64,0.18)", + headerText: "#2a5a2a", + buttonBg: "rgba(26,122,64,0.07)", + buttonHover: "rgba(26,122,64,0.15)", + link: "#0a6aaa", + }, +}; + +const COMMANDS = { + help: { + output: [ + { text: "┌─ AVAILABLE COMMANDS ─────────────────────────────┐", color: "accent" }, + { text: "│ help Show this help menu │", color: "text" }, + { text: "│ about About Satyam Kumar Verman │", color: "text" }, + { text: "│ skills Technical skill set │", color: "text" }, + { text: "│ projects Projects with live links │", color: "text" }, + { text: "│ links All social & profile links │", color: "text" }, + { text: "│ achievements Certs · contests · open source │", color: "text" }, + { text: "│ contact Get in touch │", color: "text" }, + { text: "│ clear Clear terminal output │", color: "text" }, + { text: "│ reset Reset to initial state │", color: "text" }, + { text: "│ theme Toggle dark / light mode │", color: "text" }, + { text: "│ banner Show ASCII banner │", color: "text" }, + { text: "└───────────────────────────────────────────────────┘", color: "accent" }, + ], + }, + + about: { + output: [ + { text: "▸ SATYAM KUMAR VERMAN", color: "accent" }, + { text: " Full-Stack Developer · DSA · Open Source · AI-Augmented Dev", color: "text" }, + { text: "", color: "text" }, + { text: " Self-taught developer with strong foundations in DS&A, OS,", color: "muted" }, + { text: " Networking & System Design. Built Omezle — a WebRTC platform", color: "muted" }, + { text: " handling 20K+ concurrent users. Active open-source contributor", color: "muted" }, + { text: " to freeCodeCamp & CPython. 500+ DSA problems solved.", color: "muted" }, + { text: "", color: "text" }, + { text: " Status → Available for hire", color: "prompt" }, + { text: " Location → Ramgarh, Jharkhand, India", color: "prompt" }, + { text: " Phone → +91 6200872019", color: "prompt" }, + { type: "link", prefix: " Email → ", label: "satyamkumarverman@gmail.com", url: "mailto:satyamkumarverman@gmail.com", color: "prompt" }, + ], + }, + + skills: { + output: [ + { text: "▸ TECHNICAL SKILLS", color: "accent" }, + { text: "", color: "text" }, + { text: " Languages Python · C++ · JavaScript · Java · C", color: "text" }, + { text: "", color: "text" }, + { text: " Frontend React.js · HTML5/CSS3 · ES6+ · WebSockets", color: "text" }, + { text: " WebRTC · RESTful API · Responsive Design", color: "text" }, + { text: "", color: "text" }, + { text: " Backend Node.js · Express.js · Flask · MongoDB", color: "text" }, + { text: " REST API · System Design (HLD + LLD)", color: "text" }, + { text: "", color: "text" }, + { text: " DevOps Linux (Ubuntu/CLI) · Git · Docker", color: "text" }, + { text: " Vercel · Render · Railway.app", color: "text" }, + { text: "", color: "text" }, + { text: " CS Core DSA · OS · Networking · DBMS · OOP", color: "text" }, + { text: " SDLC · Penetration Testing", color: "text" }, + { text: "", color: "text" }, + { text: " AI Tools ChatGPT · Google Gemini · Claude", color: "muted" }, + ], + }, + + projects: { + output: [ + { text: "▸ PROJECTS", color: "accent" }, + { text: "", color: "text" }, + { text: " [01] Omezle — Real-Time Random Chat Web App", color: "text" }, + { text: " MERN + WebRTC · 20K+ concurrent users · Socket.IO", color: "muted" }, + { text: " Matchmaking · rate limiting · moderation · microservices WIP", color: "muted" }, + { type: "link", prefix: " → Live: ", label: "omezle.xyz", url: "https://omezle.xyz", color: "accent" }, + { text: "", color: "text" }, + { text: " [02] Terminal Theme Portfolio", color: "text" }, + { text: " You're inside it! Interactive terminal-based UI portfolio.", color: "muted" }, + { text: " Stack: React · Node.js · Express · MongoDB · Vercel", color: "muted" }, + { text: "", color: "text" }, + { text: " [03] URL Shortener Web App", color: "text" }, + { text: " Flask REST API · long URLs → short slugs · minimal UI", color: "muted" }, + { text: " Stack: Python · Flask · REST API · Vercel", color: "muted" }, + { text: "", color: "text" }, + { text: " [04] Pomodoro Timer Web App", color: "text" }, + { text: " Real-time WebSocket sync · session tracking · modern UI", color: "muted" }, + { text: " Stack: Python · Flask · WebSockets · Vercel", color: "muted" }, + ], + }, + + links: { + output: [ + { text: "▸ LINKS & PROFILES", color: "accent" }, + { text: "", color: "text" }, + { type: "link", prefix: " ✉ Email → ", label: "satyamkumarverman@gmail.com", url: "mailto:satyamkumarverman@gmail.com", color: "prompt" }, + { type: "link", prefix: " ⌥ GitHub → ", label: "Github", url: "https://github.com/skvprogrammer", color: "accent" }, + { type: "link", prefix: " ◈ LinkedIn → ", label: "LinkedIn", url: "https://www.linkedin.com/in/satyam-kumar-verman-b77272190/", color: "accent" }, + { type: "link", prefix: " ⚡ Portfolio → ", label: "Live portfolio", url: "#", color: "accent" }, + { type: "link", prefix: " ⊞ LeetCode → ", label: "Leetcode", url: "https://leetcode.com/u/skvprogrammer", color: "accentDim" }, + { type: "link", prefix: " ◉ Omezle → ", label: "Omezle", url: "https://omezle.xyz", color: "accentDim" }, + { text: "", color: "text" }, + { text: " → Open to full-time roles & collaborations.", color: "muted" }, + ], + }, + + achievements: { + output: [ + { text: "▸ ACHIEVEMENTS & CERTIFICATIONS", color: "accent" }, + { text: "", color: "text" }, + { text: " DSA", color: "accent" }, + { text: " ⬡ 500+ problems solved on LeetCode & HackerRank", color: "text" }, + { text: " ⬡ LeetCode Rank #125 — Weekly Contest 477", color: "text" }, + { text: " ⬡ LeetCode Rank #453 — Biweekly Contest 170", color: "text" }, + { text: "", color: "text" }, + { text: " Open Source", color: "accent" }, + { type: "link", prefix: " ⬡ freeCodeCamp → ", label: "4–5 PRs merged into main curriculum", url: "https://github.com/freeCodeCamp/freeCodeCamp", color: "text" }, + { type: "link", prefix: " ⬡ CPython → ", label: "1 PR merged into official Python interpreter", url: "https://github.com/python/cpython", color: "text" }, + { text: "", color: "text" }, + { text: " Certifications", color: "accent" }, + { text: " ⬡ C++ Programming — Beginner to Ultimate Level (Udemy)", color: "muted" }, + { text: " ⬡ Software Engineer Role Certification", color: "muted" }, + { text: " ⬡ Penetration Testing Certification", color: "muted" }, + { text: " ⬡ HackerRank — Java · Python · SQL", color: "muted" }, + ], + }, + + contact: { + output: [ + { text: "▸ CONTACT SATYAM", color: "accent" }, + { text: "", color: "text" }, + { type: "link", prefix: " ✉ ", label: "satyamkumarverman@gmail.com", url: "mailto:satyamkumarverman@gmail.com", color: "prompt" }, + { text: " ☎ +91 6200872019", color: "text" }, + { type: "link", prefix: " ⌥ GitHub → ", label: "Github", url: "https://github.com/skvprogrammer", color: "accent" }, + { type: "link", prefix: " ◈ LinkedIn → ", label: "LinkedIn", url: "https://www.linkedin.com/in/satyam-kumar-verman-b77272190/", color: "accent" }, + { text: "", color: "text" }, + { text: " → Open to full-time roles & collaborations.", color: "prompt" }, + ], + }, + + banner: { + output: [ + { text: " ███████╗██╗ ██╗██╗ ██╗", color: "accent" }, + { text: " ██╔════╝██║ ██╔╝██║ ██║", color: "accent" }, + { text: " ███████╗█████╔╝ ██║ ██║", color: "accentDim" }, + { text: " ╚════██║██╔═██╗ ╚██╗ ██╔╝", color: "accentDim" }, + { text: " ███████║██║ ██╗ ╚████╔╝ ", color: "muted" }, + { text: " ╚══════╝╚═╝ ╚═╝ ╚═══╝ ", color: "muted" }, + { text: "", color: "text" }, + { text: " Full-Stack Dev · DSA · Open Source · AI Dev", color: "prompt" }, + { text: " Type 'help' to explore · Type 'links' for socials", color: "muted" }, + ], + }, + + reset: { + output: [ + { text: "Resetting terminal...", color: "muted" }, + ], + }, +}; + +const BOOT_SEQUENCE = [ + "Initializing system...", + "Loading profile: satyam@portfolio", + "Mounting filesystem...", + "Starting terminal session...", + "", + "Session ready. Type 'help' to get started.", +]; + +function GlowCursor({ theme }) { + const t = THEMES[theme]; + return ( + + ); +} + +export default function Terminal() { + const [theme, setTheme] = useState("dark"); + const [output, setOutput] = useState([]); + const [command, setCommand] = useState(""); + const [history, setHistory] = useState([]); + const [historyIdx, setHistoryIdx] = useState(-1); + const [booted, setBooted] = useState(false); + const [focused, setFocused] = useState(false); + const [isMobile, setIsMobile] = useState(window.innerWidth < 768); + const [, setPersistentOutput] = useState([]); // Stores boot + banner + const bodyRef = useRef(null); + const inputRef = useRef(null); + const t = THEMES[theme]; + + // Detect mobile and listen for resize + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth < 768); + }; + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); +const outputRef = useRef([]); + +useEffect(() => { + outputRef.current = output; +}, [output]); + +useEffect(() => { + let i = 0; + const interval = setInterval(() => { + if (i < BOOT_SEQUENCE.length) { + const idx = i; + const line = BOOT_SEQUENCE[idx]; + setOutput((prev) => [ + ...prev, + { + type: "boot", + text: line, + color: + idx === BOOT_SEQUENCE.length - 1 + ? "accent" + : idx < 3 + ? "prompt" + : "muted", + }, + ]); + i++; + } else { + clearInterval(interval); + + const bannerOutput = { + type: "out", + lines: COMMANDS.banner.output, + }; + + setOutput((prev) => [...prev, bannerOutput]); + + setPersistentOutput((prev) => [ + ...prev, + ...outputRef.current, + bannerOutput, + ]); + + setBooted(true); + setTimeout(() => inputRef.current?.focus(), 50); } - 51%, 100% { - opacity: 0; + }, 150); + + return () => clearInterval(interval); +}, []); + // Auto-scroll + useEffect(() => { + bodyRef.current?.scrollTo({ top: bodyRef.current.scrollHeight, behavior: "smooth" }); + }, [output]); + + const resolveColor = useCallback( + (colorKey) => { + const map = { + accent: t.accent, + accentDim: t.accentDim, + text: t.text, + muted: t.muted, + prompt: t.prompt, + error: t.error, + link: t.link, + }; + return map[colorKey] || t.text; + }, + [t] + ); + + const runCommand = useCallback((raw) => { + const cmd = raw.trim().toLowerCase(); + if (!cmd) return; + setHistory((prev) => [raw, ...prev].slice(0, 50)); + setHistoryIdx(-1); + setOutput((prev) => [...prev, { type: "cmd", text: raw }]); + + if (cmd === "clear") { + // Clear command now restores the initial banner and boot sequence + setTimeout(() => { + setOutput([ + { + type: "boot", + text: "Visit Omezle.xyz! ", + color: "muted", + }, + { type: "out", lines: COMMANDS.banner.output }, + ]); + }, 100); + return; } - } -`; - -const ThemeToggle = styled.button` - background: none; - border: 1px solid ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; - color: ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; - padding: 10px 10px; - border-radius: 50%; - cursor: pointer; - font-size: 14px; - transition: all 0.3s; - - &:hover { - background: ${(props) => (props.theme === "dark" ? "#ff0000" : "#333")}; - color: ${(props) => (props.theme === "dark" ? "#000" : "#fff")}; - } -`; - -const Terminal = () => { - const [command, setCommand] = useState(""); - const [output, setOutput] = useState([]); - const [theme, setTheme] = useState("dark"); + + if (cmd === "reset") { + // Reset command shows boot sequence all over again + setTimeout(() => { + setOutput([]); + let i = 0; + const interval = setInterval(() => { + if (i < BOOT_SEQUENCE.length) { + const idx = i; + const line = BOOT_SEQUENCE[idx]; + setOutput((prev) => [ + ...prev, + { + type: "boot", + text: line, + color: idx === BOOT_SEQUENCE.length - 1 ? "accent" : idx < 3 ? "prompt" : "muted", + }, + ]); + i++; + } else { + clearInterval(interval); + setOutput((prev) => [...prev, { type: "out", lines: COMMANDS.banner.output }]); + } + }, 150); + }, 100); + return; + } + + if (cmd === "theme") { + setTheme((prev) => (prev === "dark" ? "light" : "dark")); + setOutput((prev) => [...prev, { type: "out", lines: [{ text: "Theme toggled.", color: "accent" }] }]); + return; + } + const def = COMMANDS[cmd]; + if (def) { + setOutput((prev) => [...prev, { type: "out", lines: def.output }]); + } else { + setOutput((prev) => [ + ...prev, + { + type: "out", + lines: [ + { text: `bash: ${raw}: command not found`, color: "error" }, + { text: "Type 'help' to see available commands.", color: "muted" }, + ], + }, + ]); + } + }, []); - const handleCommand = (e) => { + const handleKeyDown = (e) => { if (e.key === "Enter") { - const newOutput = [...output]; - switch (command.trim().toLowerCase()) { - case "about": - newOutput.length=0; - newOutput.push( - "I am a competitive programmer skilled in React, Node.js, and more.\n" + - "I also explore machine learning, blockchain, and ethical hacking." - ); - break; - case "skills": - newOutput.length=0; - newOutput.push( - "Skills:\n" + - "- Programming: C,C++, Python, JavaScript,Java,\n" + - "- Machine Learning: TensorFlow, PyTorch\n" + - "- Web Dev: MERN , Flask , Django\n" + - "- Blockchain: Solidity, Ethereum\n" + - "- Ethical Hacking: Kali Linux, Metasploit" - ); - break; - case "projects": - newOutput.length=0; - newOutput.push( - "Projects:\n" + - "- URL Shortner\n" + - "- Random Chat Web App\n" + - "- Personal Portfolio Terminal\n" + - "- Whiteboard Web App\n" + - "- Notes Web App\n" - - ); - break; - case "hobbies": - newOutput.length=0; - newOutput.push( - "Hobbies:\n" + - "- Solving competitive programming challenges\n" + - "- Ethical hacking\n" + - "- Exploring AI advancements" - ); - break; - // case "achievements": - // newOutput.push( - // "Achievements:\n" + - // "- B\n" + - // "- Built a blockchain app with 100+ active users\n" + - // "- Completed advanced ethical hacking certification" - // ); - // break; - case "goals": - newOutput.length=0; - newOutput.push( - "Goals:\n" + - "- Build scalable AI-based systems\n" + - "- Contribute to open-source blockchain projects\n" + - "- Participate in global hackathons" - ); - break; - case "contact": - newOutput.length=0; - newOutput.push( - "Contact Information:\n" + - "- Email: satyamkumarverman@gmail.com\n" + - "- GitHub: https://github.com/skvprogrammer\n" + - "- Linktree: https://linktr.ee/skvprogrammer" - ); - break; - case "help": - newOutput.length=0; - newOutput.push( - "Available commands:\n" + - "- about: Learn about me\n" + - "- skills: See my skill set\n" + - "- projects: Explore my projects\n" + - "- hobbies: Know what I do for fun\n" + - "- achievements: See my accomplishments\n" + - "- goals: My future ambitions\n" + - "- contact: Get my contact info\n" + - "- clear: Clear the terminal" - ); - break; - case "clear": - setOutput([]); - setCommand(""); - return; - default: - newOutput.push(`'${command}' is not recognized as a command.`); - } - setOutput(newOutput); + runCommand(command); setCommand(""); + } else if (e.key === "ArrowUp") { + e.preventDefault(); + const next = Math.min(historyIdx + 1, history.length - 1); + setHistoryIdx(next); + setCommand(history[next] || ""); + } else if (e.key === "ArrowDown") { + e.preventDefault(); + const next = Math.max(historyIdx - 1, -1); + setHistoryIdx(next); + setCommand(next === -1 ? "" : history[next] || ""); + } else if (e.key === "Tab") { + e.preventDefault(); + const cmds = Object.keys(COMMANDS).concat(["clear", "theme"]); + const match = cmds.find((c) => c.startsWith(command.toLowerCase())); + if (match) setCommand(match); } }; - return ( - - - {/* - - - - - - SATYAM KUMAR VERMAN - I like to work with tech - | GitHub | - | Linktree | - -

- -
*/} - {/* -
Satyam Kumar Verman I love to work with tech
-
*/} - setTheme(theme === "dark" ? "light" : "dark")} + const renderLine = (l, j) => { + if (l.type !== "link" && (l.text === "" || l.text === undefined)) { + return
; + } + if (l.type === "link") { + return ( +
- {theme === "dark" ? : } - - Developer Logo { - e.currentTarget.style.transform = "scale(1.05)"; - e.currentTarget.style.filter = "drop-shadow(0 0 15px #00ffee)"; - }} - onMouseOut={(e) => { - e.currentTarget.style.transform = "scale(1)"; - e.currentTarget.style.filter = "drop-shadow(0 0 10px #00ffcc)"; - }} -/> - -
+ ); + } + return ( +
+ {l.text} +
+ ); + }; + // Responsive font sizes and spacing + const fontSize = isMobile ? "12px" : "13.5px"; + const padding = isMobile ? "12px 16px" : "18px 24px"; + const inputPadding = isMobile ? "10px 16px" : "11px 24px"; + const headerPadding = isMobile ? "8px 12px" : "10px 18px"; + const lineHeight = isMobile ? "1.6" : "1.75"; + const bottomPadding = isMobile ? "0px" : "12px"; + // const footerGap = isMobile ? "12px" : "20px"; + return ( + <> + + +
inputRef.current?.focus()} + > + {/* CRT scanlines */} + {theme === "dark" && ( +
- -
- {output.map((line, index) => ( - - {line.split("\n").map((text, idx) => ( - - {text} -
-
+ )} + + {/* HEADER */} +
+
+
+ {["#ff5f57", "#febc2e", "#28c840"].map((c, i) => ( +
))} - - ))} +
+ + satyam@portfolio + +
+
- - - root@kali - - setCommand(e.target.value)} - onKeyDown={handleCommand} + + {/* SCROLLABLE OUTPUT */} +
- - - - ); -}; + > + {output.map((line, i) => { + if (line.type === "boot") + return ( +
+ {line.text === "" ?
: {"› "}{line.text}} +
+ ); + if (line.type === "cmd") + return ( +
+ root + @ + kali + :~$  + + {line.text} + +
+ ); + if (line.type === "out") + return ( +
+ {line.lines.map((l, j) => renderLine(l, j))} +
+ ); + return null; + })} +
+
+ + {/* STICKY INPUT */} +
+ + root + + + @ + + + kali + + + :~$  + +
+ setCommand(e.target.value)} + onKeyDown={handleKeyDown} + onFocus={() => setFocused(true)} + onBlur={() => setFocused(false)} + disabled={!booted} + autoComplete="off" + spellCheck={false} + style={{ + flex: 1, + background: "transparent", + border: "none", + outline: "none", + color: t.text, + fontFamily: "inherit", + fontSize: fontSize, + caretColor: "transparent", + letterSpacing: "0.02em", + minWidth: 0, + padding: 0, + }} + /> + {booted && focused && } +
+
-export default Terminal; + {/* KEYBOARD HINTS - Hidden on mobile, shown on larger screens */} + {!isMobile && ( +
+ {[ + ["TAB", "autocomplete"], + ["↑↓", "history"], + ["ENTER", "execute"], + ].map(([key, label]) => ( + + + {key} + + {label} + + ))} +
+ )} +
+ + ); +} \ No newline at end of file