What am I using
React, CSS modules
Hi There I am making a Portfolio Terminal
website
So, I want to make a feature where the user creates a new Line like the terminal does so, when you press enter in the terminal it creates a new line like this: Terminal New Line Image
So, as I was saying I want this same functionality but there is a problem I face where when I press enter and then try to do another command it doesn’t do the command
I hope I made this clear
here is my JSX code:
import { useEffect, useRef, useState } from "react";
import styles from "../css/TerminalPage.module.css";
function TerminalPage() {
const [textInput, setTextInput] = useState("");
const [helpValues, setHelpValues] = useState("");
const [newLine, setNewLine] = useState("");
const inputRef = useRef(null);
const help = {
about: "My Name Is Ammar Ehab and I am a Full-Stack Developer",
social: {
title: "YouTube",
url: "www.youtube.com",
},
projects: {
title: "Projects",
url: "www.yourprojectsurl.com", // Replace with your actual projects URL
},
};
useEffect(() => {
function handleKeyDown(event) {
if (event.ctrlKey && event.keyCode === 76) {
event.preventDefault();
setHelpValues("");
}
}
function handleClick() {
inputRef.current.focus();
}
// Add the event listener when the component mounts
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("click", handleClick);
// Remove the event listener when the component unmounts
return () => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("click", handleClick);
};
}, []);
function renderSocialLink() {
const socialTitle = help.social.title;
const socialUrl = help.social.url;
return (
<div className={styles.gridContainer}>
<div className={styles.gridItem}>
<span>{socialTitle}</span>
</div>
<div className={styles.gridItem}>
<span className={styles.gridItemUrl}>{socialUrl}</span>
</div>
</div>
);
}
function checkHelpCommand() {
const trimmedInput = textInput.trim().toLowerCase();
if (trimmedInput === "help") {
const commands = Object.keys(help);
setHelpValues(
commands.map((command, index) => <span key={index}>{command}</span>)
);
} else if (trimmedInput === "about") {
setHelpValues(help.about);
} else if (trimmedInput === "social") {
setHelpValues(renderSocialLink());
} else if (trimmedInput === "clear") {
setHelpValues("");
} else if (trimmedInput === "") {
setNewLine("newLine");
} else {
setHelpValues(
`command not found ${trimmedInput}. Type "help" for more information`
);
}
}
function handleSubmit(e) {
e.preventDefault();
checkHelpCommand();
setTextInput("");
}
return (
<div className={styles.terminalContainer}>
<form onSubmit={(e) => handleSubmit(e)}>
<div className={styles.terminalInputContainer}>
<div>
<span className={styles.terminalKeyword}>
guest<span>@</span>ammar.com:<span>~$</span>
</span>
</div>
<input
value={textInput}
onChange={(e) => setTextInput(e.target.value)}
ref={inputRef}
/>
</div>
<div>
<div>
<div className={styles.textareaOutput}>
{Array.isArray(helpValues)
? helpValues.map((element, index) => (
<div key={index} className={styles.commandBlock}>
{element}
</div>
))
: helpValues}
</div>
</div>
<div style={{ display: "block" }}>
{newLine === "newLine" ? (
<div className={styles.terminalInputContainer}>
<div>
<span className={styles.terminalKeyword}>
guest<span>@</span>ammar.com:<span>~$</span>
</span>
</div>
<input
value={textInput}
onChange={(e) => setTextInput(e.target.value)}
ref={inputRef}
/>
</div>
) : null}
</div>
</div>
</form>
</div>
);
}
export default TerminalPage;
and here are my styles if needed:
:root {
--main-text-color: #a16b56;
--text-input-color: #73abad;
--main-color: #e2d7a7;
--text-url-hover: #1a4645;
--text-url-color: #f8bc24;
--user-text-color: rgb(81, 153, 117);
}
.terminalContainer {
margin: 10px 0 0 10px;
}
.terminalContainer * {
color: var(--text-color);
}
.terminalContainer .input-container {
position: relative;
}
.terminalContainer .input-container::before {
content: "visitor@Ammar:$ ~ ";
color: white;
background-color: #333;
padding: 5px;
position: absolute;
top: 0;
left: 0;
height: 100%;
}
.terminalContainer input {
border: none;
outline: none;
resize: none;
background-color: var(--main-color);
color: var(--text-input-color);
/* Add a text-shadow for the glow effect */
text-shadow: 0 0 5px rgba(115, 171, 173, 0.5); /* Adjust the values as needed */
}
.terminalContainer input:hover {
border: none;
outline: none;
cursor: text;
}
.terminalContainer textarea:hover,
.terminalContainer input:hover {
border: none;
outline: none;
cursor: text;
}
.terminalInputContainer {
display: flex;
align-items: center;
}
.terminalInputContainer div .terminalKeyword {
letter-spacing: -1px;
font-size: large;
}
.terminalKeyword {
color: var(--user-text-color);
}
.terminalKeyword span {
color: var(--main-text-color);
}
.terminalInputContainer input {
width: 100%;
margin: 0 0 0 5px;
height: 100px;
font-size: 1.2rem;
color: var(--text-input-color);
}
.textareaOutput {
background-color: var(--main-color);
resize: none;
border: none;
font-size: 1.1rem;
}
.gridContainer {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: 10px;
width: 500px;
}
.gridItemUrl {
transition: all 0.2s ease;
width: fit-content;
color: var(--text-url-color);
padding: 5px;
transform: translateY(-5px);
cursor: pointer;
}
.gridItemUrl:hover {
background-color: var(--text-url-hover);
}
/* Grid items within the container */
.gridItem {
background-color: var(--main-color);
padding: 10px;
border-radius: 5px;
color: var(--main-text-color);
}
.gridItem span {
display: block; /* Display URLs on a new line */
font-size: 1rem;
font-weight: bold;
}
.commandBlock {
background-color: var(--main-color);
padding: 10px;
border-radius: 5px;
margin-bottom: 5px;
color: var(--text-input-color);
font-size: 1rem;
font-weight: bold;
text-shadow: 0 0 5px rgba(115, 171, 173, 0.5),
0 0 10px rgba(115, 171, 173, 0.5), 0 0 15px rgba(115, 171, 173, 0.5);
}