Skip to content

Commit ef75bee

Browse files
committed
add terminal
1 parent e543cf8 commit ef75bee

3 files changed

Lines changed: 167 additions & 1 deletion

File tree

‎frontend/src/App.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Experience from "./components/Experience";
66
import Projects from "./components/Projects";
77
import Skills from "./components/Skills";
88
import Contact from "./components/Contact";
9+
import Terminal from "./components/Terminal";
910

1011
const App: Component = () => {
1112
return (
@@ -19,6 +20,7 @@ const App: Component = () => {
1920
<Skills />
2021
<Contact />
2122
</main>
23+
<Terminal />
2224
</div>
2325
);
2426
};

‎frontend/src/components/Hero.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const Hero: Component = () => {
3535
const flickerInterval = setInterval(() => {
3636
setVisible(false);
3737
setTimeout(() => setVisible(true), 100);
38-
}, 3000);
38+
}, 2000);
3939

4040
// Change name occasionally
4141
const nameInterval = setInterval(() => {
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import type { Component } from "solid-js";
2+
import { createSignal, For, onMount } from "solid-js";
3+
4+
type CommandOutput = {
5+
command: string;
6+
output: string;
7+
};
8+
9+
const Terminal: Component = () => {
10+
const [input, setInput] = createSignal("");
11+
const [history, setHistory] = createSignal<CommandOutput[]>([]);
12+
const [historyIndex, setHistoryIndex] = createSignal(-1);
13+
let inputRef: HTMLInputElement | undefined;
14+
15+
const commands: Record<string, string> = {
16+
help: `Available commands:
17+
help - Show this help message
18+
about - Jump to About section
19+
experience - Jump to Experience section
20+
projects - Jump to Projects section
21+
skills - Jump to Skills section
22+
contact - Jump to Contact section
23+
whoami - Display system info
24+
clear - Clear terminal output
25+
ls - List available sections`,
26+
27+
whoami: `Parth Sharma (aka pipboi / darth)
28+
Software Engineer @ General Motors
29+
Building scalable apps for 17K+ users
30+
Location: Texas, USA`,
31+
32+
ls: `total 6
33+
drwxr-xr-x about/
34+
drwxr-xr-x experience/
35+
drwxr-xr-x projects/
36+
drwxr-xr-x skills/
37+
drwxr-xr-x contact/`,
38+
39+
about: "Navigating to About section...",
40+
experience: "Navigating to Experience section...",
41+
projects: "Navigating to Projects section...",
42+
skills: "Navigating to Skills section...",
43+
contact: "Navigating to Contact section...",
44+
};
45+
46+
const handleCommand = (cmd: string) => {
47+
const trimmedCmd = cmd.trim().toLowerCase();
48+
49+
if (trimmedCmd === "clear") {
50+
setHistory([]);
51+
return;
52+
}
53+
54+
let output = "";
55+
56+
if (trimmedCmd === "") {
57+
return;
58+
} else if (commands[trimmedCmd]) {
59+
output = commands[trimmedCmd];
60+
61+
// Navigate to sections
62+
if (["about", "experience", "projects", "skills", "contact", "home"].includes(trimmedCmd)) {
63+
const element = document.getElementById(trimmedCmd);
64+
if (element) {
65+
setTimeout(() => {
66+
element.scrollIntoView({ behavior: "smooth", block: "start" });
67+
}, 100);
68+
}
69+
}
70+
} else {
71+
output = `Command not found: ${trimmedCmd}
72+
Type 'help' for available commands.`;
73+
}
74+
75+
setHistory([...history(), { command: cmd, output }]);
76+
setInput("");
77+
78+
// Scroll to bottom after adding output
79+
setTimeout(() => {
80+
const terminalOutput = document.getElementById("terminal-output");
81+
if (terminalOutput) {
82+
terminalOutput.scrollTop = terminalOutput.scrollHeight;
83+
}
84+
}, 50);
85+
};
86+
87+
const handleKeyDown = (e: KeyboardEvent) => {
88+
if (e.key === "Enter") {
89+
handleCommand(input());
90+
} else if (e.key === "ArrowUp") {
91+
e.preventDefault();
92+
const allCommands = history().map(h => h.command);
93+
if (allCommands.length > 0) {
94+
const newIndex = historyIndex() === -1 ? allCommands.length - 1 : Math.max(0, historyIndex() - 1);
95+
setHistoryIndex(newIndex);
96+
setInput(allCommands[newIndex] || "");
97+
}
98+
} else if (e.key === "ArrowDown") {
99+
e.preventDefault();
100+
const allCommands = history().map(h => h.command);
101+
if (historyIndex() !== -1) {
102+
const newIndex = Math.min(allCommands.length - 1, historyIndex() + 1);
103+
setHistoryIndex(newIndex);
104+
setInput(allCommands[newIndex] || "");
105+
}
106+
} else if (e.key === "Tab") {
107+
e.preventDefault();
108+
const currentInput = input().toLowerCase();
109+
const matches = Object.keys(commands).filter(cmd => cmd.startsWith(currentInput));
110+
if (matches.length === 1) {
111+
setInput(matches[0]);
112+
}
113+
}
114+
};
115+
116+
onMount(() => {
117+
// Show welcome message
118+
setHistory([{
119+
command: "",
120+
output: `Welcome to Parth's Terminal Portfolio!
121+
Type 'help' to see available commands.`
122+
}]);
123+
});
124+
125+
return (
126+
<div class="fixed bottom-4 right-4 w-full max-w-2xl z-50 px-4">
127+
<div class="terminal-window p-4 max-h-96 flex flex-col">
128+
{/* Output area */}
129+
<div id="terminal-output" class="flex-1 overflow-y-auto mb-4 space-y-2 text-sm">
130+
<For each={history()}>
131+
{(item) => (
132+
<div>
133+
{item.command && (
134+
<div class="text-[#5bff4d]">
135+
<span class="text-white">$</span> {item.command}
136+
</div>
137+
)}
138+
<pre class="text-gray-300 whitespace-pre-wrap font-mono text-sm">{item.output}</pre>
139+
</div>
140+
)}
141+
</For>
142+
</div>
143+
144+
{/* Input area */}
145+
<div class="flex items-center gap-2 border-t border-gray-700 pt-2">
146+
<span class="text-[#5bff4d]">$</span>
147+
<input
148+
ref={inputRef}
149+
type="text"
150+
value={input()}
151+
onInput={(e) => setInput(e.currentTarget.value)}
152+
onKeyDown={handleKeyDown}
153+
class="flex-1 bg-transparent text-white outline-none font-mono"
154+
placeholder="Type 'help' for commands..."
155+
autocomplete="off"
156+
spellcheck={false}
157+
/>
158+
</div>
159+
</div>
160+
</div>
161+
);
162+
};
163+
164+
export default Terminal;

0 commit comments

Comments
 (0)